diff --git a/common/io/eagle/eagle_parser.cpp b/common/io/eagle/eagle_parser.cpp index e3abd070fb..f0baf3a652 100644 --- a/common/io/eagle/eagle_parser.cpp +++ b/common/io/eagle/eagle_parser.cpp @@ -1476,7 +1476,7 @@ EELEMENT::EELEMENT( wxXmlNode* aElement, IO_BASE* aIo ) : library = parseRequiredAttribute( aElement, "library" ); value = parseRequiredAttribute( aElement, "value" ); std::string p = parseRequiredAttribute( aElement, "package" ); - ReplaceIllegalFileNameChars( &p, '_' ); + ReplaceIllegalFileNameChars( p, '_' ); package = wxString::FromUTF8( p.c_str() ); x = parseRequiredAttribute( aElement, "x" ); @@ -1732,7 +1732,7 @@ EDEVICE::EDEVICE( wxXmlNode* aDevice, IO_BASE* aIo ) : if( pack ) { std::string p( pack->c_str() ); - ReplaceIllegalFileNameChars( &p, '_' ); + ReplaceIllegalFileNameChars( p, '_' ); package.Set( wxString::FromUTF8( p.c_str() ) ); } diff --git a/common/string_utils.cpp b/common/string_utils.cpp index 93604511b9..b892cafb55 100644 --- a/common/string_utils.cpp +++ b/common/string_utils.cpp @@ -48,7 +48,7 @@ * platforms. This is the list of illegal file name characters for Windows which includes * the illegal file name characters for Linux and OSX. */ -static const char illegalFileNameChars[] = "\\/:\"<>|*?"; +static constexpr std::string_view illegalFileNameChars = "\\/:\"<>|*?"; static const wxChar defaultVariantName[] = wxT( "< Default >" ); @@ -1323,37 +1323,49 @@ int GetTrailingInt( const wxString& aStr ) wxString GetIllegalFileNameWxChars() { - return From_UTF8( illegalFileNameChars ); + return wxString::FromUTF8( illegalFileNameChars.data(), illegalFileNameChars.length() ); } -bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar ) +bool ReplaceIllegalFileNameChars( std::string& aName, int aReplaceChar ) { - bool changed = false; - std::string result; - result.reserve( aName->length() ); + size_t first_illegal_pos = aName.find_first_of( illegalFileNameChars ); - for( std::string::iterator it = aName->begin(); it != aName->end(); ++it ) + if( first_illegal_pos == std::string::npos ) { - if( strchr( illegalFileNameChars, *it ) ) + return false; + } + + std::string result; + // result will be at least equal to original, add 16 in case of hex replacements + result.reserve( aName.length() + 16 ); + // append the valid part + result.append( aName, 0, first_illegal_pos ); + + for( size_t i = first_illegal_pos; i < aName.length(); ++i ) + { + char c = aName[i]; + + // Check if this specific char is illegal + if( illegalFileNameChars.find( c ) != std::string_view::npos ) { if( aReplaceChar ) - StrPrintf( &result, "%c", aReplaceChar ); + { + result.push_back( aReplaceChar ); + } else - StrPrintf( &result, "%%%02x", *it ); - - changed = true; + { + fmt::format_to( std::back_inserter( result ), "%{:02x}", static_cast( c ) ); + } } else { - result += *it; + result.push_back( c ); } } - if( changed ) - *aName = std::move( result ); - - return changed; + aName = std::move( result ); + return true; } diff --git a/eeschema/sch_io/cadstar/cadstar_sch_archive_loader.cpp b/eeschema/sch_io/cadstar/cadstar_sch_archive_loader.cpp index 0d52aaea71..626418d723 100644 --- a/eeschema/sch_io/cadstar/cadstar_sch_archive_loader.cpp +++ b/eeschema/sch_io/cadstar/cadstar_sch_archive_loader.cpp @@ -585,7 +585,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheets() std::string filename = wxString::Format( "%s_%02d", loadedFilePath.GetName(), getSheetNumber( rootSheetID ) ) .ToStdString(); - ReplaceIllegalFileNameChars( &filename ); + ReplaceIllegalFileNameChars( filename ); filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension ); wxFileName fn( m_schematic->Project().GetProjectPath() + filename ); @@ -2481,7 +2481,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheetAndChildSheets( const LAYER_ID& wxString loadedFilename = wxFileName( Filename ).GetName(); std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString(); - ReplaceIllegalFileNameChars( &filename ); + ReplaceIllegalFileNameChars( filename ); filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension ); sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( filename ); diff --git a/eeschema/sch_io/eagle/sch_io_eagle.cpp b/eeschema/sch_io/eagle/sch_io_eagle.cpp index 3e6cc55368..970ec1ac59 100644 --- a/eeschema/sch_io/eagle/sch_io_eagle.cpp +++ b/eeschema/sch_io/eagle/sch_io_eagle.cpp @@ -852,7 +852,7 @@ void SCH_IO_EAGLE::loadSheet( const std::unique_ptr& aSheet ) else sheet->SetName( filename ); - ReplaceIllegalFileNameChars( &filename ); + ReplaceIllegalFileNameChars( filename ); replace( filename.begin(), filename.end(), ' ', '_' ); fn.SetName( filename ); diff --git a/include/string_utils.h b/include/string_utils.h index 81d107dcff..3ad5f9737f 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -286,7 +286,7 @@ KICOMMON_API bool IsFullFileNameValid( const wxString& aFullFilename ); * @param aReplaceChar (if not 0) is the replacement char. * @return true if any characters have been replaced in \a aName. */ -KICOMMON_API bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar = 0 ); +KICOMMON_API bool ReplaceIllegalFileNameChars( std::string& aName, int aReplaceChar = 0 ); KICOMMON_API bool ReplaceIllegalFileNameChars( wxString& aName, int aReplaceChar = 0 ); diff --git a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp index c7516de447..02f5b3f32a 100644 --- a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp +++ b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp @@ -541,7 +541,7 @@ void PCB_IO_KICAD_LEGACY::loadAllSections( bool doAppend ) // The footprint names in legacy libraries can contain the '/' and ':' // characters which will cause the FPID parser to choke. - ReplaceIllegalFileNameChars( &fpName ); + ReplaceIllegalFileNameChars( fpName ); if( !fpName.empty() ) fpid.Parse( fpName, true ); @@ -3171,7 +3171,7 @@ void LP_CACHE::LoadModules( LINE_READER* aReader ) // The footprint names in legacy libraries can contain the '/' and ':' // characters which will cause the LIB_ID parser to choke. - ReplaceIllegalFileNameChars( &footprintName ); + ReplaceIllegalFileNameChars( footprintName ); // set the footprint name first thing, so exceptions can use name. fp_ptr->SetFPID( LIB_ID( wxEmptyString, footprintName ) ); diff --git a/qa/tests/common/CMakeLists.txt b/qa/tests/common/CMakeLists.txt index ea5658cf8a..a1f49a0a15 100644 --- a/qa/tests/common/CMakeLists.txt +++ b/qa/tests/common/CMakeLists.txt @@ -61,6 +61,7 @@ set( QA_COMMON_SRCS test_reporting.cpp test_refdes_utils.cpp test_grid_helper.cpp + test_string_utils.cpp test_richio.cpp test_text_attributes.cpp text_eval/test_text_eval_parser.cpp