kicad2step: fix broken handing of UTF8 filenames.

the conversion between UTF8 std::strings and wxString were missing in some places.
3D model: fix management of file having double ext .stp.gz
Fixes #9038
https://gitlab.com/kicad/code/kicad/issues/9038
This commit is contained in:
jean-pierre charras 2021-08-27 14:34:49 +02:00
parent f6287053e5
commit 4670309ec1
4 changed files with 48 additions and 29 deletions

View File

@ -406,18 +406,23 @@ std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const no
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo ) SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo )
{ {
wxFileName raw( aFileName ); wxFileName raw( aFileName );
wxString ext = raw.GetExt(); wxString ext_to_find = raw.GetExt();
#ifdef _WIN32 #ifdef _WIN32
// note: plugins only have a lowercase filter within Windows; including an uppercase // note: plugins only have a lowercase filter within Windows; including an uppercase
// filter will result in duplicate file entries and should be avoided. // filter will result in duplicate file entries and should be avoided.
ext.LowerCase(); ext_to_find.MakeLower();
#endif #endif
// When the extension is .gz, the actual extension should be .stp.gz;
// So ensure is ext is the expected extension
if( ext_to_find == "gz" && aFileName.Lower().EndsWith( ".stp.gz" ) )
ext_to_find = "stp.gz";
std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator, std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator,
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items; std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items;
items = m_ExtMap.equal_range( ext ); items = m_ExtMap.equal_range( ext_to_find );
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first; std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
while( sL != items.second ) while( sL != items.second )

View File

@ -76,6 +76,7 @@
#include "plugins/3dapi/ifsg_all.h" #include "plugins/3dapi/ifsg_all.h"
// log mask for wxLogTrace // log mask for wxLogTrace
#define MASK_OCE "PLUGIN_OCE" #define MASK_OCE "PLUGIN_OCE"

View File

@ -600,27 +600,28 @@ bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
} }
bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aRefDes, bool PCBMODEL::AddComponent( const std::string& aFileNameUTF8, const std::string& aRefDes,
bool aBottom, DOUBLET aPosition, double aRotation, bool aBottom, DOUBLET aPosition, double aRotation,
TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale, TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale,
bool aSubstituteModels ) bool aSubstituteModels )
{ {
if( aFileName.empty() ) if( aFileNameUTF8.empty() )
{ {
ReportMessage( wxString::Format( "No model defined for component %s.\n", aRefDes ) ); ReportMessage( wxString::Format( "No model defined for component %s.\n", aRefDes ) );
return false; return false;
} }
wxString fileName( wxString::FromUTF8( aFileNameUTF8 ) );
ReportMessage( wxString::Format( "Add component %s.\n", aRefDes ) ); ReportMessage( wxString::Format( "Add component %s.\n", aRefDes ) );
// first retrieve a label // first retrieve a label
TDF_Label lmodel; TDF_Label lmodel;
wxString errorMessage; wxString errorMessage;
if( !getModelLabel( aFileName, aScale, lmodel, aSubstituteModels, &errorMessage ) ) if( !getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
{ {
if( errorMessage.IsEmpty() ) if( errorMessage.IsEmpty() )
ReportMessage( wxString::Format( "No model for filename '%s'.\n", aFileName ) ); ReportMessage( wxString::Format( "No model for filename '%s'.\n", fileName ) );
else else
ReportMessage( errorMessage ); ReportMessage( errorMessage );
@ -632,7 +633,7 @@ bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aR
if( !getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) ) if( !getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
{ {
ReportMessage( wxString::Format( "No location data for filename '%s'.\n", aFileName ) ); ReportMessage( wxString::Format( "No location data for filename '%s'.\n", fileName ) );
return false; return false;
} }
@ -642,7 +643,7 @@ bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aR
if( llabel.IsNull() ) if( llabel.IsNull() )
{ {
ReportMessage( wxString::Format( "Could not add component with filename '%s'.\n", ReportMessage( wxString::Format( "Could not add component with filename '%s'.\n",
aFileName ) ); fileName ) );
return false; return false;
} }
@ -978,10 +979,10 @@ bool PCBMODEL::WriteSTEP( const wxString& aFileName )
} }
bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_Label& aLabel, bool PCBMODEL::getModelLabel( const std::string& aFileNameUTF8, TRIPLET aScale, TDF_Label& aLabel,
bool aSubstituteModels, wxString* aErrorMessage ) bool aSubstituteModels, wxString* aErrorMessage )
{ {
std::string model_key = aFileName + "_" + std::to_string( aScale.x ) std::string model_key = aFileNameUTF8 + "_" + std::to_string( aScale.x )
+ "_" + std::to_string( aScale.y ) + "_" + std::to_string( aScale.z ); + "_" + std::to_string( aScale.y ) + "_" + std::to_string( aScale.z );
MODEL_MAP::const_iterator mm = m_models.find( model_key ); MODEL_MAP::const_iterator mm = m_models.find( model_key );
@ -997,39 +998,42 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
Handle( TDocStd_Document ) doc; Handle( TDocStd_Document ) doc;
m_app->NewDocument( "MDTV-XCAF", doc ); m_app->NewDocument( "MDTV-XCAF", doc );
FormatType modelFmt = fileType( aFileName.c_str() ); wxString fileName( wxString::FromUTF8( aFileNameUTF8 ) );
FormatType modelFmt = fileType( aFileNameUTF8.c_str() );
switch( modelFmt ) switch( modelFmt )
{ {
case FMT_IGES: case FMT_IGES:
if( !readIGES( doc, aFileName.c_str() ) ) if( !readIGES( doc, aFileNameUTF8.c_str() ) )
{ {
ReportMessage( wxString::Format( "readIGES() failed on filename '%s'.\n", aFileName ) ); ReportMessage( wxString::Format( "readIGES() failed on filename '%s'.\n", fileName ) );
return false; return false;
} }
break; break;
case FMT_STEP: case FMT_STEP:
if( !readSTEP( doc, aFileName.c_str() ) ) if( !readSTEP( doc, aFileNameUTF8.c_str() ) )
{ {
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", aFileName ) ); ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", fileName ) );
return false; return false;
} }
break; break;
case FMT_STEPZ: case FMT_STEPZ:
{ {
wxFFileInputStream ifile( aFileName ); // To export a compressed step file (.stpz or .stp.gz file), the best way is to
wxFileName outFile( aFileName ); // decaompress it in a temporaty file and load this temporary file
wxFFileInputStream ifile( fileName );
wxFileName outFile( fileName );
outFile.SetPath( wxStandardPaths::Get().GetTempDir() ); outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
outFile.SetExt( "STEP" ); outFile.SetExt( "step" );
wxFileOffset size = ifile.GetLength(); wxFileOffset size = ifile.GetLength();
if( size == wxInvalidOffset ) if( size == wxInvalidOffset )
{ {
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", aFileName ) ); ReportMessage( wxString::Format( "getModelLabel() failed on filename '%s'.\n",
fileName ) );
return false; return false;
} }
@ -1052,6 +1056,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
} }
catch( ... ) catch( ... )
{ {
ReportMessage( wxString::Format( "failed to decompress '%s'.\n", fileName ) );
} }
if( expanded.empty() ) if( expanded.empty() )
@ -1075,6 +1080,12 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
delete[] buffer; delete[] buffer;
ofile.Close(); ofile.Close();
if( success )
{
std::string altFileNameUTF8 = outFile.GetFullPath().utf8_string();
success = getModelLabel( altFileNameUTF8, TRIPLET( 1.0, 1.0, 1.0 ), aLabel, false );
}
return success; return success;
} }
@ -1093,7 +1104,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
*/ */
if( aSubstituteModels ) if( aSubstituteModels )
{ {
wxFileName wrlName( aFileName ); wxFileName wrlName( fileName );
wxString basePath = wrlName.GetPath(); wxString basePath = wrlName.GetPath();
wxString baseName = wrlName.GetName(); wxString baseName = wrlName.GetName();
@ -1114,6 +1125,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
alts.Add( "stpZ" ); alts.Add( "stpZ" );
alts.Add( "STPZ" ); alts.Add( "STPZ" );
alts.Add( "step.gz" ); alts.Add( "step.gz" );
alts.Add( "stp.gz" );
// IGES files // IGES files
alts.Add( "iges" ); alts.Add( "iges" );
@ -1129,7 +1141,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
if( altFile.IsOk() && altFile.FileExists() ) if( altFile.IsOk() && altFile.FileExists() )
{ {
std::string altFileName = altFile.GetFullPath().ToStdString(); std::string altFileNameUTF8 = altFile.GetFullPath().utf8_string();
// When substituting a STEP/IGS file for VRML, do not apply the VRML scaling // When substituting a STEP/IGS file for VRML, do not apply the VRML scaling
// to the new STEP model. This process of auto-substitution is janky as all // to the new STEP model. This process of auto-substitution is janky as all
@ -1138,7 +1150,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
// named "model.wrl" and "model.stp" referring to different parts. // named "model.wrl" and "model.stp" referring to different parts.
// TODO: Fix model handling in v7. Default models should only be STP. // TODO: Fix model handling in v7. Default models should only be STP.
// Have option to override this in DISPLAY. // Have option to override this in DISPLAY.
if( getModelLabel( altFileName, TRIPLET( 1.0, 1.0, 1.0 ), aLabel, false ) ) if( getModelLabel( altFileNameUTF8, TRIPLET( 1.0, 1.0, 1.0 ), aLabel, false ) )
{ {
return true; return true;
} }
@ -1168,13 +1180,13 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
if( aLabel.IsNull() ) if( aLabel.IsNull() )
{ {
ReportMessage( wxString::Format( "Could not transfer model data from file '%s'.\n", ReportMessage( wxString::Format( "Could not transfer model data from file '%s'.\n",
aFileName ) ); fileName ) );
return false; return false;
} }
// attach the PART NAME ( base filename: note that in principle // attach the PART NAME ( base filename: note that in principle
// different models may have the same base filename ) // different models may have the same base filename )
wxFileName afile( aFileName.c_str() ); wxFileName afile( fileName );
std::string pname( afile.GetName().ToUTF8() ); std::string pname( afile.GetName().ToUTF8() );
TCollection_ExtendedString partname( pname.c_str() ); TCollection_ExtendedString partname( pname.c_str() );
TDataStd_Name::Set( aLabel, partname ); TDataStd_Name::Set( aLabel, partname );

View File

@ -125,15 +125,16 @@ private:
/** /**
* Load a 3D model data. * Load a 3D model data.
* *
* @param aFileName is the filename (different formats allowed) but for WRML files a model * @param aFileNameUTF8 is the filename encoded UTF8 (different formats allowed)
* data can be loaded instead of the vrml data, not suitable in a step file. * but for WRML files a model data can be loaded instead of the vrml data,
* not suitable in a step file.
* @param aScale is the X,Y,Z scaling factors. * @param aScale is the X,Y,Z scaling factors.
* @param aLabel is the TDF_Label to store the data. * @param aLabel is the TDF_Label to store the data.
* @param aSubstituteModels = true to allows data substitution, false to disallow. * @param aSubstituteModels = true to allows data substitution, false to disallow.
* @param aErrorMessage (can be nullptr) is an error message to be displayed on error. * @param aErrorMessage (can be nullptr) is an error message to be displayed on error.
* @return true if successfully loaded, false on error. * @return true if successfully loaded, false on error.
*/ */
bool getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_Label& aLabel, bool getModelLabel( const std::string& aFileNameUTF8, TRIPLET aScale, TDF_Label& aLabel,
bool aSubstituteModels, wxString* aErrorMessage = nullptr ); bool aSubstituteModels, wxString* aErrorMessage = nullptr );
bool getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation, TRIPLET aOffset, bool getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation, TRIPLET aOffset,