Eeschema: fix UTF8 character handling bug in legacy parser.

Iterating over unquoted strings as ASCII8 fails when ' ' character is
not the LSB of a UTF8 string with wide characters.  Change parsing method
for unquoted strings to convert the entire line as UTF8 and then use
wxStringTokenizer to break the line into tokens at the ' ' characters.

Fixes lp:1806206

https://bugs.launchpad.net/kicad/+bug/1806206

(cherry picked from commit a61a51f26e)
This commit is contained in:
Wayne Stambaugh 2018-12-05 13:54:51 -05:00
parent 4aeef1e09e
commit 61b94c8c2c
1 changed files with 70 additions and 35 deletions

View File

@ -2426,8 +2426,10 @@ void SCH_LEGACY_PLUGIN_CACHE::loadDocs()
if( !strCompare( "$CMP", line, &line ) != 0 ) if( !strCompare( "$CMP", line, &line ) != 0 )
SCH_PARSE_ERROR( "$CMP command expected", reader, line ); SCH_PARSE_ERROR( "$CMP command expected", reader, line );
parseUnquotedString( aliasName, reader, line, &line ); // Alias name. aliasName = wxString::FromUTF8( line );
aliasName.Trim();
aliasName = LIB_ID::FixIllegalChars( aliasName, LIB_ID::ID_SCH ); aliasName = LIB_ID::FixIllegalChars( aliasName, LIB_ID::ID_SCH );
LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasName ); LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasName );
if( it == m_aliases.end() ) if( it == m_aliases.end() )
@ -2509,32 +2511,63 @@ LIB_PART* SCH_LEGACY_PLUGIN_CACHE::loadPart( FILE_LINE_READER& aReader )
wxCHECK( strCompare( "DEF", line, &line ), NULL ); wxCHECK( strCompare( "DEF", line, &line ), NULL );
// Read DEF line: long num;
char yes_no = 0; size_t pos = 4; // "DEF" plus the first space.
wxString utf8Line = wxString::FromUTF8( line );
wxStringTokenizer tokens( utf8Line, " \r\n\t" );
if( tokens.CountTokens() < 8 )
SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
// Read DEF line:
std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) ); std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) );
wxString name, prefix; wxString name, prefix, tmp;
parseUnquotedString( name, aReader, line, &line ); // Part name. name = tokens.GetNextToken();
parseUnquotedString( prefix, aReader, line, &line ); // Prefix name pos += name.size() + 1;
parseInt( aReader, line, &line ); // NumOfPins, unused.
part->SetPinNameOffset( parseInt( aReader, line, &line ) ); // Pin name offset.
yes_no = parseChar( aReader, line, &line ); // Show pin numbers.
if( !( yes_no == 'Y' || yes_no == 'N') ) prefix = tokens.GetNextToken();
SCH_PARSE_ERROR( "expected Y or N", aReader, line ); pos += prefix.size() + 1;
part->SetShowPinNumbers( ( yes_no == 'N' ) ? false : true ); tmp = tokens.GetNextToken();
pos += tmp.size() + 1; // NumOfPins, unused.
yes_no = parseChar( aReader, line, &line ); // Show pin numbers. tmp = tokens.GetNextToken(); // Pin name offset.
if( !( yes_no == 'Y' || yes_no == 'N') ) if( !tmp.ToLong( &num ) )
SCH_PARSE_ERROR( "expected Y or N", aReader, line ); THROW_PARSE_ERROR( "invalid pin offset", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
part->SetShowPinNames( ( yes_no == 'N' ) ? false : true ); // Show pin names. pos += tmp.size() + 1;
part->SetPinNameOffset( (int)num );
part->SetUnitCount( parseInt( aReader, line, &line ) ); // Number of units. tmp = tokens.GetNextToken(); // Show pin numbers.
if( !( tmp == "Y" || tmp == "N") )
THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
pos += tmp.size() + 1;
part->SetShowPinNumbers( ( tmp == "N" ) ? false : true );
tmp = tokens.GetNextToken(); // Show pin names.
if( !( tmp == "Y" || tmp == "N") )
THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
pos += tmp.size() + 1;
part->SetShowPinNames( ( tmp == "N" ) ? false : true );
tmp = tokens.GetNextToken(); // Number of units.
if( !tmp.ToLong( &num ) )
THROW_PARSE_ERROR( "invalid unit count", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
pos += tmp.size() + 1;
part->SetUnitCount( (int)num );
// Ensure m_unitCount is >= 1. Could be read as 0 in old libraries. // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
if( part->GetUnitCount() < 1 ) if( part->GetUnitCount() < 1 )
@ -2583,32 +2616,36 @@ LIB_PART* SCH_LEGACY_PLUGIN_CACHE::loadPart( FILE_LINE_READER& aReader )
{ {
// Nothing needs to be set since the default setting for symbols with multiple // Nothing needs to be set since the default setting for symbols with multiple
// units were never interchangeable. Just parse the 0 an move on. // units were never interchangeable. Just parse the 0 an move on.
parseInt( aReader, line, &line ); tmp = tokens.GetNextToken();
pos += tmp.size() + 1;
} }
else else
{ {
char locked = parseChar( aReader, line, &line ); tmp = tokens.GetNextToken();
if( locked == 'L' ) if( tmp == "L" )
part->LockUnits( true ); part->LockUnits( true );
else if( locked == 'F' || locked == '0' ) else if( tmp == "F" || tmp == "0" )
part->LockUnits( false ); part->LockUnits( false );
else else
SCH_PARSE_ERROR( "expected L, F, or 0", aReader, line ); THROW_PARSE_ERROR( "expected L, F, or 0", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
pos += tmp.size() + 1;
} }
// There is the optional power component flag. // There is the optional power component flag.
if( *line ) if( tokens.HasMoreTokens() )
{ {
char power = parseChar( aReader, line, &line ); tmp = tokens.GetNextToken();
if( power == 'P' ) if( tmp == "P" )
part->SetPower(); part->SetPower();
else if( power == 'N' ) else if( tmp == "N" )
part->SetNormal(); part->SetNormal();
else else
SCH_PARSE_ERROR( "expected P or N", aReader, line ); THROW_PARSE_ERROR( "expected P or N", aReader.GetSource(), aReader.Line(),
aReader.LineNumber(), pos );
} }
line = aReader.ReadLine(); line = aReader.ReadLine();
@ -2713,17 +2750,15 @@ void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" ); wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
// Parse the ALIAS list. wxString utf8Line = wxString::FromUTF8( line );
wxString alias; wxStringTokenizer tokens( utf8Line, " \r\n\t" );
parseUnquotedString( alias, aReader, line, &line );
while( !alias.IsEmpty() ) // Parse the ALIAS list.
while( tokens.HasMoreTokens() )
{ {
newAlias = alias; newAlias = tokens.GetNextToken();
checkForDuplicates( newAlias ); checkForDuplicates( newAlias );
aPart->AddAlias( newAlias ); aPart->AddAlias( newAlias );
alias.clear();
parseUnquotedString( alias, aReader, line, &line, true );
} }
} }