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 )
{
wxFileName raw( aFileName );
wxString ext = raw.GetExt();
wxString ext_to_find = raw.GetExt();
#ifdef _WIN32
// note: plugins only have a lowercase filter within Windows; including an uppercase
// filter will result in duplicate file entries and should be avoided.
ext.LowerCase();
ext_to_find.MakeLower();
#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::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;
while( sL != items.second )

View File

@ -76,6 +76,7 @@
#include "plugins/3dapi/ifsg_all.h"
// log mask for wxLogTrace
#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,
TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale,
bool aSubstituteModels )
{
if( aFileName.empty() )
if( aFileNameUTF8.empty() )
{
ReportMessage( wxString::Format( "No model defined for component %s.\n", aRefDes ) );
return false;
}
wxString fileName( wxString::FromUTF8( aFileNameUTF8 ) );
ReportMessage( wxString::Format( "Add component %s.\n", aRefDes ) );
// first retrieve a label
TDF_Label lmodel;
wxString errorMessage;
if( !getModelLabel( aFileName, aScale, lmodel, aSubstituteModels, &errorMessage ) )
if( !getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
{
if( errorMessage.IsEmpty() )
ReportMessage( wxString::Format( "No model for filename '%s'.\n", aFileName ) );
ReportMessage( wxString::Format( "No model for filename '%s'.\n", fileName ) );
else
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 ) )
{
ReportMessage( wxString::Format( "No location data for filename '%s'.\n", aFileName ) );
ReportMessage( wxString::Format( "No location data for filename '%s'.\n", fileName ) );
return false;
}
@ -642,7 +643,7 @@ bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aR
if( llabel.IsNull() )
{
ReportMessage( wxString::Format( "Could not add component with filename '%s'.\n",
aFileName ) );
fileName ) );
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 )
{
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 );
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;
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 )
{
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;
}
break;
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;
}
break;
case FMT_STEPZ:
{
wxFFileInputStream ifile( aFileName );
wxFileName outFile( aFileName );
// To export a compressed step file (.stpz or .stp.gz file), the best way is to
// decaompress it in a temporaty file and load this temporary file
wxFFileInputStream ifile( fileName );
wxFileName outFile( fileName );
outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
outFile.SetExt( "STEP" );
outFile.SetExt( "step" );
wxFileOffset size = ifile.GetLength();
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;
}
@ -1052,6 +1056,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
}
catch( ... )
{
ReportMessage( wxString::Format( "failed to decompress '%s'.\n", fileName ) );
}
if( expanded.empty() )
@ -1075,6 +1080,12 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
delete[] buffer;
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;
}
@ -1093,7 +1104,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
*/
if( aSubstituteModels )
{
wxFileName wrlName( aFileName );
wxFileName wrlName( fileName );
wxString basePath = wrlName.GetPath();
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( "step.gz" );
alts.Add( "stp.gz" );
// IGES files
alts.Add( "iges" );
@ -1129,7 +1141,7 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
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
// 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.
// TODO: Fix model handling in v7. Default models should only be STP.
// 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;
}
@ -1168,13 +1180,13 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
if( aLabel.IsNull() )
{
ReportMessage( wxString::Format( "Could not transfer model data from file '%s'.\n",
aFileName ) );
fileName ) );
return false;
}
// attach the PART NAME ( base filename: note that in principle
// different models may have the same base filename )
wxFileName afile( aFileName.c_str() );
wxFileName afile( fileName );
std::string pname( afile.GetName().ToUTF8() );
TCollection_ExtendedString partname( pname.c_str() );
TDataStd_Name::Set( aLabel, partname );

View File

@ -125,15 +125,16 @@ private:
/**
* Load a 3D model data.
*
* @param aFileName is the filename (different formats allowed) but for WRML files a model
* data can be loaded instead of the vrml data, not suitable in a step file.
* @param aFileNameUTF8 is the filename encoded UTF8 (different formats allowed)
* 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 aLabel is the TDF_Label to store the data.
* @param aSubstituteModels = true to allows data substitution, false to disallow.
* @param aErrorMessage (can be nullptr) is an error message to be displayed 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 getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation, TRIPLET aOffset,