Fix symbol names with illegal library ID characters.

Change the legacy schematic plugin to preserve illegal LIB_ID characters
when load schematics prior to version 4.

Check for illegal LIB_ID symbol names during project rescue.  Rename and
rescue any symbols with illegal LIB_ID names.

Add static methods to LIB_ID object for testing for and fixing names
with illegal characters so there is uniform code for doing so.

Update the Eagle plugin symbol loader to fix symbol names using the new
LIB_ID fix illegal names method.

Fixes lp:1732236

https://bugs.launchpad.net/kicad/+bug/1732236
This commit is contained in:
Wayne Stambaugh 2017-11-23 10:52:28 -05:00
parent d52fd5769d
commit b82bd8e0c5
5 changed files with 114 additions and 62 deletions

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2016 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2010-2016 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2010-2017 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -359,6 +359,62 @@ int LIB_ID::compare( const LIB_ID& aLibId ) const
}
bool LIB_ID::HasIllegalChars( const UTF8& aLibItemName )
{
for( auto ch : aLibItemName )
{
switch( ch )
{
case '\t':
case '\n':
case '\r':
case ':':
case '/':
return true;
}
if( !wxIsascii( ch ) )
return true;
}
return false;
}
UTF8 LIB_ID::FixIllegalChars( const UTF8& aLibItemName )
{
UTF8 fixedName;
for( auto ch : aLibItemName )
{
if( !wxIsascii( ch ) )
{
fixedName += '_';
}
else
{
switch( ch )
{
case '\t':
case '\n':
case '\r':
case ':':
case '/':
case '\\':
fixedName += '_';
break;
default:
fixedName += ch;
}
}
}
return fixedName;
}
#if 0 && defined(DEBUG)
// build this with Debug CMAKE_BUILD_TYPE

View File

@ -258,14 +258,15 @@ void RESCUE_CACHE_CANDIDATE::FindRescues( RESCUER& aRescuer,
if( !cache_match && !lib_match )
continue;
// Test whether there is a conflict or if the symbol can only be found in the cache.
if( ( cache_match && lib_match
// Test whether there is a conflict or if the symbol can only be found in the cache
// and the symbol name does not have any illegal characters.
if( ( ( cache_match && lib_match
&& !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
|| (!cache_match && lib_match ) )
|| (!cache_match && lib_match ) ) && !LIB_ID::HasIllegalChars( part_name ) )
continue;
// Check if the symbol has already been rescued.
wxString new_name = part_name;
wxString new_name = LIB_ID::FixIllegalChars( part_name );
if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
new_name += part_name_suffix;
@ -371,13 +372,14 @@ void RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::FindRescues(
continue;
// Test whether there is a conflict or if the symbol can only be found in the cache.
if( ( cache_match && lib_match
if( ( ( cache_match && lib_match
&& !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
|| (!cache_match && lib_match ) )
&& !LIB_ID::HasIllegalChars( part_id.GetLibItemName() ) )
continue;
// May have been rescued already.
wxString new_name = part_id.GetLibItemName();
wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName() );
if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
new_name += part_name_suffix;

View File

@ -1055,10 +1055,10 @@ void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode )
package = p->second;
}
std::string kisymbolname = symbolname;
std::replace( kisymbolname.begin(), kisymbolname.end(), ':', '_' );
std::replace( kisymbolname.begin(), kisymbolname.end(), '/', '_' );
std::replace( kisymbolname.begin(), kisymbolname.end(), '"', '_' );
std::string kisymbolname = LIB_ID::FixIllegalChars( symbolname );
// std::replace( kisymbolname.begin(), kisymbolname.end(), ':', '_' );
// std::replace( kisymbolname.begin(), kisymbolname.end(), '/', '_' );
// std::replace( kisymbolname.begin(), kisymbolname.end(), '"', '_' );
LIB_ALIAS* alias = m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname,
m_properties.get() );
@ -1263,10 +1263,10 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode,
if( gates_count == 1 && ispower )
kpart->SetPower();
string name = kpart->GetName().ToStdString();
std::replace( name.begin(), name.end(), ':', '_' );
std::replace( name.begin(), name.end(), '/', '_' );
std::replace( name.begin(), name.end(), '"', '_' );
string name = LIB_ID::FixIllegalChars( kpart->GetName().ToStdString() );
// std::replace( name.begin(), name.end(), ':', '_' );
// std::replace( name.begin(), name.end(), '/', '_' );
// std::replace( name.begin(), name.end(), '"', '_' );
kpart->SetName( name );
m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_PART( *kpart.get() ),
m_properties.get() );

View File

@ -1377,7 +1377,13 @@ SCH_COMPONENT* SCH_LEGACY_PLUGIN::loadComponent( FILE_LINE_READER& aReader )
LIB_ID libId;
// Prior to schematic version 4, library IDs did not have a library nickname so
// parsing the symbol name with LIB_ID::Parse() would break symbol library links
// that contained '/' and ':' characters.
if( m_version > 3 )
libId.Parse( libName );
else
libId.SetLibItemName( libName, false );
component->SetLibId( libId );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2010-2017 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -30,9 +30,8 @@
#include <utf8.h>
/**
* Class LIB_ID
* A logical library item identifier and consists of various portions much like a URI.
*
* is a logical library item identifier and consists of various portions much like a URI.
* It consists of of triad of the library nickname, the name of the item in the library,
* and an optional revision of the item. This is a generic library identifier that can be
* used for any type of library that contains multiple named items such as footprint or
@ -41,15 +40,11 @@
* Example LIB_ID string:
* "smt:R_0805/rev0".
*
* <p>
* <ul>
* <li> "smt" is the logical library name used to look up library information saved in the
* #LIB_TABLE.
* <li> "R" is the name of the item within the library.
* <li> "rev0" is the revision, which is optional. If missing then its
* / delimiter should also not be present. A revision must begin with
* "rev" and be followed by at least one or more decimal digits.
* </ul>
* - "smt" is the logical library name used to look up library information saved in the #LIB_TABLE.
* - "R" is the name of the item within the library.
* - "rev0" is the revision, which is optional. If missing then its delimiter should also not
* be present. A revision must begin with "rev" and be followed by at least one or more
* decimal digits.
*
* @author Dick Hollenbeck
*/
@ -60,10 +55,9 @@ public:
LIB_ID() {}
/**
* Constructor LIB_ID
* Takes \a aId string and parses it.
*
* takes \a aId string and parses it. A typical LIB_ID string consists of a
* library nickname followed by a library item name.
* A typical LIB_ID string consists of a library nickname followed by a library item name.
* e.g.: "smt:R_0805", or
* e.g.: "mylib:R_0805", or
* e.g.: "ttl:7400"
@ -88,9 +82,7 @@ public:
const wxString& aRevision = wxEmptyString );
/**
* Function Parse
*
* [re-]stuffs this LIB_ID with the information from @a aId.
* Parse LIB_ID with the information from @a aId.
*
* @param aId is the string to populate the #LIB_ID object.
*
@ -101,9 +93,7 @@ public:
/**
* Function GetLibNickname
*
* returns the logical library name portion of a LIB_ID.
* Return the logical library name portion of a LIB_ID.
*/
const UTF8& GetLibNickname() const
{
@ -111,9 +101,7 @@ public:
}
/**
* Function SetLibNickname
*
* overrides the logical library name portion of the LIB_ID to @a aNickname.
* Override the logical library name portion of the LIB_ID to @a aNickname.
*
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset
* into the parameter at which an error was detected, usually because it
@ -122,16 +110,12 @@ public:
int SetLibNickname( const UTF8& aNickname );
/**
* Function GetLibItemName
*
* @return the library item name, i.e. footprintName.
*/
const UTF8& GetLibItemName() const { return item_name; }
/**
* Function SetLibItemName
*
* overrides the library item name portion of the LIB_ID to @a aLibItemName
* Override the library item name portion of the LIB_ID to @a aLibItemName
*
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset
* into the parameter at which an error was detected, usually because it
@ -146,15 +130,11 @@ public:
UTF8 GetLibItemNameAndRev() const;
/**
* Function Format
*
* @return the fully formatted text of the LIB_ID.
*/
UTF8 Format() const;
/**
* Function Format
*
* @return a string in the proper format as an LIB_ID for a combination of
* aLibNickname, aLibItemName, and aRevision.
*
@ -164,8 +144,6 @@ public:
const UTF8& aRevision = "" );
/**
* Function IsValid
*
* @return true is the #LIB_ID is valid.
*
* A valid #LIB_ID must have both the library nickname and the library item name defined.
@ -177,22 +155,16 @@ public:
bool IsValid() const { return !nickname.empty() && !item_name.empty(); }
/**
* Function IsLegacy
*
* @return true if the #LIB_ID only has the #item_name name defined.
*/
bool IsLegacy() const { return nickname.empty() && !item_name.empty() && revision.empty(); }
/**
* Function clear
*
* clears the contents of the library nickname, library entry name, and revision strings.
* Clear the contents of the library nickname, library entry name, and revision strings.
*/
void clear();
/**
* Function empty
*
* @return a boolean true value if the LIB_ID is empty. Otherwise return false.
*/
bool empty() const { return nickname.empty() && item_name.empty() && revision.empty(); }
@ -212,6 +184,22 @@ public:
bool operator ==( const LIB_ID& aLibId ) const { return this->compare( aLibId ) == 0; }
bool operator !=( const LIB_ID& aLibId ) const { return !(*this == aLibId); }
/**
* Examine \a aLibItemName for invalid #LIB_ID item name characters.
*
* @param aLibItemName is the #LIB_ID name to test for illegal characters.
* @return true if \a aLibItemName contain illegal characters otherwise false.
*/
static bool HasIllegalChars( const UTF8& aLibItemName );
/**
* Replace illegal #LIB_ID item name characters with underscores '_'.
*
* @param aLibItemName is the #LIB_ID item name to replace illegal characters.
* @return the corrected version of \a aLibItemName.
*/
static UTF8 FixIllegalChars( const UTF8& aLibItemName );
#if defined(DEBUG)
static void Test();
#endif