diff --git a/common/lib_id.cpp b/common/lib_id.cpp index 67b22bfb03..66f1335827 100644 --- a/common/lib_id.cpp +++ b/common/lib_id.cpp @@ -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 - * Copyright (C) 2012-2016 Wayne Stambaugh - * Copyright (C) 2010-2016 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2012 Wayne Stambaugh + * 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 diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp index 0a482d1c78..ed2485d583 100644 --- a/eeschema/project_rescue.cpp +++ b/eeschema/project_rescue.cpp @@ -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 - && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) ) - || (!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 ) ) && !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 - && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) ) - || (!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; diff --git a/eeschema/sch_eagle_plugin.cpp b/eeschema/sch_eagle_plugin.cpp index b2a510d888..f24e3e033e 100644 --- a/eeschema/sch_eagle_plugin.cpp +++ b/eeschema/sch_eagle_plugin.cpp @@ -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() ); diff --git a/eeschema/sch_legacy_plugin.cpp b/eeschema/sch_legacy_plugin.cpp index 04de9889d9..86b7ddc336 100644 --- a/eeschema/sch_legacy_plugin.cpp +++ b/eeschema/sch_legacy_plugin.cpp @@ -1377,7 +1377,13 @@ SCH_COMPONENT* SCH_LEGACY_PLUGIN::loadComponent( FILE_LINE_READER& aReader ) LIB_ID libId; - libId.Parse( libName ); + // 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 ); diff --git a/include/lib_id.h b/include/lib_id.h index 9a914b403e..66d86b3208 100644 --- a/include/lib_id.h +++ b/include/lib_id.h @@ -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 - * Copyright (C) 2012-2017 Wayne Stambaugh + * Copyright (C) 2012 Wayne Stambaugh * 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 /** - * 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". * - *

- *

    - *
  • "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. - *
+ * - "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