7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-03-30 06:46:34 +00:00

Fix reading old plot layer settings into new layer IDs

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19475
This commit is contained in:
Ian McInerney 2025-01-04 21:38:37 +00:00
parent 42a7aa452e
commit 43a7868994
6 changed files with 340 additions and 150 deletions

View File

@ -297,126 +297,6 @@ LSEQ LSET::TechAndUserUIOrder() const
}
std::string LSET::FmtBin() const
{
std::string ret;
int bit_count = size();
for( int bit=0; bit<bit_count; ++bit )
{
if( bit )
{
if( !( bit % 8 ) )
ret += '|';
else if( !( bit % 4 ) )
ret += '_';
}
ret += (*this)[bit] ? '1' : '0';
}
// reverse of string
return std::string( ret.rbegin(), ret.rend() );
}
std::string LSET::FmtHex() const
{
std::string ret;
static const char hex[] = "0123456789abcdef";
size_t nibble_count = ( size() + 3 ) / 4;
for( size_t nibble = 0; nibble < nibble_count; ++nibble )
{
unsigned int ndx = 0;
// test 4 consecutive bits and set ndx to 0-15
for( size_t nibble_bit = 0; nibble_bit < 4; ++nibble_bit )
{
size_t nibble_pos = nibble_bit + ( nibble * 4 );
// make sure it's not extra bits that don't exist in the bitset but need to in the
// hex format
if( nibble_pos >= size() )
break;
if( ( *this )[nibble_pos] )
ndx |= ( 1 << nibble_bit );
}
if( nibble && !( nibble % 8 ) )
ret += '_';
assert( ndx < arrayDim( hex ) );
ret += hex[ndx];
}
// reverse of string
return std::string( ret.rbegin(), ret.rend() );
}
int LSET::ParseHex( const std::string& str )
{
return ParseHex( str.c_str(), str.length() );
}
int LSET::ParseHex( const char* aStart, int aCount )
{
LSET tmp;
const char* rstart = aStart + aCount - 1;
const char* rend = aStart - 1;
const int bitcount = size();
int nibble_ndx = 0;
while( rstart > rend )
{
int cc = *rstart--;
if( cc == '_' )
continue;
int nibble;
if( cc >= '0' && cc <= '9' )
nibble = cc - '0';
else if( cc >= 'a' && cc <= 'f' )
nibble = cc - 'a' + 10;
else if( cc >= 'A' && cc <= 'F' )
nibble = cc - 'A' + 10;
else
break;
int bit = nibble_ndx * 4;
for( int ndx=0; bit<bitcount && ndx<4; ++bit, ++ndx )
if( nibble & (1<<ndx) )
tmp.set( bit );
if( bit >= bitcount )
break;
++nibble_ndx;
}
int byte_count = aStart + aCount - 1 - rstart;
assert( byte_count >= 0 );
if( byte_count > 0 )
*this = tmp;
return byte_count;
}
LSEQ LSET::Seq( const LSEQ& aSequence ) const
{
LSEQ ret;

View File

@ -26,6 +26,7 @@
#include <stdexcept>
#include <dynamic_bitset.h>
#include <core/arraydim.h>
#include <core/kicad_algo.h>
#include <kicommon.h>
@ -214,6 +215,142 @@ public:
return alg::lexicographical_compare_three_way( begin(), end(), other.begin(), other.end() ) < 0;
}
/**
* Return a binary string showing contents of this set.
*/
std::string FmtBin() const
{
std::string ret;
int bit_count = size();
for( int bit=0; bit<bit_count; ++bit )
{
if( bit )
{
if( !( bit % 8 ) )
ret += '|';
else if( !( bit % 4 ) )
ret += '_';
}
ret += (*this)[bit] ? '1' : '0';
}
// reverse of string
return std::string( ret.rbegin(), ret.rend() );
}
/**
* Return a hex string showing contents of this set.
*/
std::string FmtHex() const
{
std::string ret;
static const char hex[] = "0123456789abcdef";
size_t nibble_count = ( size() + 3 ) / 4;
for( size_t nibble = 0; nibble < nibble_count; ++nibble )
{
unsigned int ndx = 0;
// test 4 consecutive bits and set ndx to 0-15
for( size_t nibble_bit = 0; nibble_bit < 4; ++nibble_bit )
{
size_t nibble_pos = nibble_bit + ( nibble * 4 );
// make sure it's not extra bits that don't exist in the bitset but need to in the
// hex format
if( nibble_pos >= size() )
break;
if( ( *this )[nibble_pos] )
ndx |= ( 1 << nibble_bit );
}
if( nibble && !( nibble % 8 ) )
ret += '_';
assert( ndx < arrayDim( hex ) );
ret += hex[ndx];
}
// reverse of string
return std::string( ret.rbegin(), ret.rend() );
}
/**
* Convert the output of FmtHex() and replaces this set's values
* with those given in the input string. Parsing stops at the first
* non hex ASCII byte, except that marker bytes output from FmtHex are
* not terminators.
* @return int - number of bytes consumed
*/
int ParseHex( const std::string& str )
{
return ParseHex( str.c_str(), str.length() );
}
/**
* Convert the output of FmtHex() and replaces this set's values
* with those given in the input string. Parsing stops at the first
* non hex ASCII byte, except that marker bytes output from FmtHex are
* not terminators.
* @return int - number of bytes consumed
*/
int ParseHex( const char* aStart, int aCount )
{
BASE_SET tmp(size());
const char* rstart = aStart + aCount - 1;
const char* rend = aStart - 1;
const int bitcount = size();
int nibble_ndx = 0;
while( rstart > rend )
{
int cc = *rstart--;
if( cc == '_' )
continue;
int nibble;
if( cc >= '0' && cc <= '9' )
nibble = cc - '0';
else if( cc >= 'a' && cc <= 'f' )
nibble = cc - 'a' + 10;
else if( cc >= 'A' && cc <= 'F' )
nibble = cc - 'A' + 10;
else
break;
int bit = nibble_ndx * 4;
for( int ndx=0; bit<bitcount && ndx<4; ++bit, ++ndx )
if( nibble & (1<<ndx) )
tmp.set( bit );
if( bit >= bitcount )
break;
++nibble_ndx;
}
int byte_count = aStart + aCount - 1 - rstart;
assert( byte_count >= 0 );
if( byte_count > 0 )
*this = tmp;
return byte_count;
}
// Custom iterator to iterate over set bits
class KICOMMON_API set_bits_iterator
{

View File

@ -249,26 +249,6 @@ public:
}
}
/**
* Return a hex string showing contents of this LSEQ.
*/
std::string FmtHex() const;
/**
* Convert the output of FmtHex() and replaces this set's values
* with those given in the input string. Parsing stops at the first
* non hex ASCII byte, except that marker bytes output from FmtHex are
* not terminators.
* @return int - number of bytes consumed
*/
int ParseHex( const char* aStart, int aCount );
int ParseHex( const std::string& str );
/**
* Return a binary string showing contents of this LSEQ.
*/
std::string FmtBin() const;
/**
* Find the first set PCB_LAYER_ID. Returns UNDEFINED_LAYER if more
* than one is set or UNSELECTED_LAYER if none is set.

View File

@ -2482,7 +2482,7 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseSetup()
case T_pcbplotparams:
{
PCB_PLOT_PARAMS plotParams;
PCB_PLOT_PARAMS_PARSER parser( reader );
PCB_PLOT_PARAMS_PARSER parser( reader, m_requiredVersion );
// parser must share the same current line as our current PCB parser
// synchronize it.
parser.SyncLineReaderWith( *this );

View File

@ -404,18 +404,183 @@ bool PCB_PLOT_PARAMS::SetHPGLPenSpeed( int aValue )
}
PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader ) :
PCB_PLOT_PARAMS_LEXER( aReader )
PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader, int aBoardFileVersion ) :
PCB_PLOT_PARAMS_LEXER( aReader ),
m_boardFileVersion( aBoardFileVersion )
{
}
PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( char* aLine, const wxString& aSource ) :
PCB_PLOT_PARAMS_LEXER( aLine, aSource )
PCB_PLOT_PARAMS_LEXER( aLine, aSource ),
m_boardFileVersion( 0 )
{
}
/**
* These are the layer IDs from before 5e0abadb23425765e164f49ee2f893e94ddb97fc,
* and are needed for mapping old PCB files to the new layer numbering.
*/
enum LEGACY_PCB_LAYER_ID: int
{
LEGACY_UNDEFINED_LAYER = -1,
LEGACY_UNSELECTED_LAYER = -2,
LEGACY_F_Cu = 0,
LEGACY_In1_Cu,
LEGACY_In2_Cu,
LEGACY_In3_Cu,
LEGACY_In4_Cu,
LEGACY_In5_Cu,
LEGACY_In6_Cu,
LEGACY_In7_Cu,
LEGACY_In8_Cu,
LEGACY_In9_Cu,
LEGACY_In10_Cu,
LEGACY_In11_Cu,
LEGACY_In12_Cu,
LEGACY_In13_Cu,
LEGACY_In14_Cu,
LEGACY_In15_Cu,
LEGACY_In16_Cu,
LEGACY_In17_Cu,
LEGACY_In18_Cu,
LEGACY_In19_Cu,
LEGACY_In20_Cu,
LEGACY_In21_Cu,
LEGACY_In22_Cu,
LEGACY_In23_Cu,
LEGACY_In24_Cu,
LEGACY_In25_Cu,
LEGACY_In26_Cu,
LEGACY_In27_Cu,
LEGACY_In28_Cu,
LEGACY_In29_Cu,
LEGACY_In30_Cu,
LEGACY_B_Cu, // 31
LEGACY_B_Adhes,
LEGACY_F_Adhes,
LEGACY_B_Paste,
LEGACY_F_Paste,
LEGACY_B_SilkS,
LEGACY_F_SilkS,
LEGACY_B_Mask,
LEGACY_F_Mask, // 39
LEGACY_Dwgs_User,
LEGACY_Cmts_User,
LEGACY_Eco1_User,
LEGACY_Eco2_User,
LEGACY_Edge_Cuts,
LEGACY_Margin, // 45
LEGACY_B_CrtYd,
LEGACY_F_CrtYd,
LEGACY_B_Fab,
LEGACY_F_Fab, // 49
// User definable layers.
LEGACY_User_1,
LEGACY_User_2,
LEGACY_User_3,
LEGACY_User_4,
LEGACY_User_5,
LEGACY_User_6,
LEGACY_User_7,
LEGACY_User_8,
LEGACY_User_9,
LEGACY_Rescue, // 59
// Four reserved layers (60 - 63) for future expansion within the 64 bit integer limit.
LEGACY_PCB_LAYER_ID_COUNT
};
/*
* Mapping to translate a legacy layer ID into the new PCB layer IDs.
*/
static const std::map<LEGACY_PCB_LAYER_ID, PCB_LAYER_ID> s_legacyLayerIdMap{
{LEGACY_F_Cu, F_Cu},
{LEGACY_B_Cu, B_Cu},
{LEGACY_In1_Cu, In1_Cu},
{LEGACY_In2_Cu, In2_Cu},
{LEGACY_In3_Cu, In3_Cu},
{LEGACY_In4_Cu, In4_Cu},
{LEGACY_In5_Cu, In5_Cu},
{LEGACY_In6_Cu, In6_Cu},
{LEGACY_In7_Cu, In7_Cu},
{LEGACY_In8_Cu, In8_Cu},
{LEGACY_In9_Cu, In9_Cu},
{LEGACY_In10_Cu, In10_Cu},
{LEGACY_In11_Cu, In11_Cu},
{LEGACY_In12_Cu, In12_Cu},
{LEGACY_In13_Cu, In13_Cu},
{LEGACY_In14_Cu, In14_Cu},
{LEGACY_In15_Cu, In15_Cu},
{LEGACY_In16_Cu, In16_Cu},
{LEGACY_In17_Cu, In17_Cu},
{LEGACY_In18_Cu, In18_Cu},
{LEGACY_In19_Cu, In19_Cu},
{LEGACY_In20_Cu, In20_Cu},
{LEGACY_In21_Cu, In21_Cu},
{LEGACY_In22_Cu, In22_Cu},
{LEGACY_In23_Cu, In23_Cu},
{LEGACY_In24_Cu, In24_Cu},
{LEGACY_In25_Cu, In25_Cu},
{LEGACY_In26_Cu, In26_Cu},
{LEGACY_In27_Cu, In27_Cu},
{LEGACY_In28_Cu, In28_Cu},
{LEGACY_In29_Cu, In29_Cu},
{LEGACY_In30_Cu, In30_Cu},
{LEGACY_F_Mask, F_Mask},
{LEGACY_B_Mask, B_Mask},
{LEGACY_F_SilkS, F_SilkS},
{LEGACY_B_SilkS, B_SilkS},
{LEGACY_F_Adhes, F_Adhes},
{LEGACY_B_Adhes, B_Adhes},
{LEGACY_F_Paste, F_Paste},
{LEGACY_B_Paste, B_Paste},
{LEGACY_Dwgs_User, Dwgs_User},
{LEGACY_Cmts_User, Cmts_User},
{LEGACY_Eco1_User, Eco1_User},
{LEGACY_Eco2_User, Eco2_User},
{LEGACY_Edge_Cuts, Edge_Cuts},
{LEGACY_Margin, Margin},
{LEGACY_B_CrtYd, B_CrtYd},
{LEGACY_F_CrtYd, F_CrtYd},
{LEGACY_B_Fab, B_Fab},
{LEGACY_F_Fab, F_Fab},
{LEGACY_User_1, User_1},
{LEGACY_User_2, User_2},
{LEGACY_User_3, User_3},
{LEGACY_User_4, User_4},
{LEGACY_User_5, User_5},
{LEGACY_User_6, User_6},
{LEGACY_User_7, User_7},
{LEGACY_User_8, User_8},
{LEGACY_User_9, User_9},
{LEGACY_Rescue, Rescue},
};
LSET remapLegacyLayerLSET( const BASE_SET& aLegacyLSET )
{
LSET newLayers;
for( const auto& [legacyLayer, newLayer] : s_legacyLayerIdMap )
newLayers[newLayer] = aLegacyLSET[legacyLayer];
return newLayers;
}
void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
{
T token;
@ -451,8 +616,21 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
}
else if( cur.find_first_of( "0x" ) == 0 ) // pretty ver. 4.
{
// skip the leading 2 0x bytes.
aPcbPlotParams->m_layerSelection.ParseHex( cur.c_str() + 2, cur.size() - 2 );
// The layers were renumbered in 5e0abadb23425765e164f49ee2f893e94ddb97fc, but there wasn't
// a board file version change with it, so this value is the one immediately after that happened.
if( m_boardFileVersion < 20240819 )
{
BASE_SET legacyLSET( LEGACY_PCB_LAYER_ID_COUNT );
// skip the leading 2 0x bytes.
legacyLSET.ParseHex( cur.c_str() + 2, cur.size() - 2 );
aPcbPlotParams->SetLayerSelection( remapLegacyLayerLSET( legacyLSET ) );
}
else
{
// skip the leading 2 0x bytes.
aPcbPlotParams->m_layerSelection.ParseHex( cur.c_str() + 2, cur.size() - 2 );
}
}
else
{
@ -470,9 +648,22 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
if( cur.find_first_of( "0x" ) == 0 )
{
// skip the leading 2 0x bytes.
aPcbPlotParams->m_plotOnAllLayersSelection.ParseHex( cur.c_str() + 2,
cur.size() - 2 );
// The layers were renumbered in 5e0abadb23425765e164f49ee2f893e94ddb97fc, but there wasn't
// a board file version change with it, so this value is the one immediately after that happened.
if( m_boardFileVersion < 20240819 )
{
BASE_SET legacyLSET( LEGACY_PCB_LAYER_ID_COUNT );
// skip the leading 2 0x bytes.
legacyLSET.ParseHex( cur.c_str() + 2, cur.size() - 2 );
aPcbPlotParams->SetPlotOnAllLayersSelection( remapLegacyLayerLSET( legacyLSET ) );
}
else
{
// skip the leading 2 0x bytes.
aPcbPlotParams->m_plotOnAllLayersSelection.ParseHex( cur.c_str() + 2,
cur.size() - 2 );
}
}
else
{

View File

@ -37,7 +37,7 @@ class LINE_READER;
class PCB_PLOT_PARAMS_PARSER : public PCB_PLOT_PARAMS_LEXER
{
public:
PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader );
PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader, int aBoardFileVersion );
PCB_PLOT_PARAMS_PARSER( char* aLine, const wxString& aSource );
LINE_READER* GetReader() { return reader; };
@ -69,6 +69,8 @@ private:
* Search for the RIGHT parenthesis which closes the current description.
*/
void skipCurrent();
int m_boardFileVersion;
};
#endif // PCB_PLOT_PARAMS_PARSER_H_