diff --git a/common/filename_resolver.cpp b/common/filename_resolver.cpp index 530659d58e..1daeb1b1e4 100644 --- a/common/filename_resolver.cpp +++ b/common/filename_resolver.cpp @@ -499,88 +499,6 @@ bool FILENAME_RESOLVER::addPath( const SEARCH_PATH& aPath ) } -bool FILENAME_RESOLVER::WritePathList( const wxString& aDir, const wxString& aFilename, - bool aResolvePaths ) -{ - if( aDir.empty() ) - { - std::ostringstream ostr; - ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; - wxString errmsg = _( "3D configuration directory is unknown" ); - ostr << " * " << errmsg.ToUTF8(); - wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() ); - wxMessageBox( errmsg, _( "Write 3D search path list" ) ); - - return false; - } - - std::list::const_iterator sPL = m_paths.begin(); - - if( !aResolvePaths ) - { - // skip all ${ENV_VAR} alias names - - while( sPL != m_paths.end() - && ( sPL->m_Alias.StartsWith( "${" ) || sPL->m_Alias.StartsWith( "$(" ) ) ) - { - ++sPL; - } - } - - wxFileName cfgpath( aDir, aFilename ); - wxString cfgname = cfgpath.GetFullPath(); - std::ofstream cfgFile; - - cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc ); - - if( !cfgFile.is_open() ) - { - std::ostringstream ostr; - ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; - wxString errmsg = _( "Could not open configuration file" ); - ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'"; - wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() ); - wxMessageBox( errmsg, _( "Write 3D search path list" ) ); - - return false; - } - - cfgFile << "#V" << CFGFILE_VERSION << "\n"; - std::string tstr; - - while( sPL != m_paths.end() ) - { - tstr = sPL->m_Alias.ToUTF8(); - cfgFile << "\"" << tstr.size() << ":" << tstr << "\","; - - if( aResolvePaths ) - tstr = ExpandEnvVarSubstitutions( sPL->m_Pathvar, m_project ).ToUTF8(); - else - tstr = sPL->m_Pathvar.ToUTF8(); - - cfgFile << "\"" << tstr.size() << ":" << tstr << "\","; - - tstr = sPL->m_Description.ToUTF8(); - cfgFile << "\"" << tstr.size() << ":" << tstr << "\"\n"; - - ++sPL; - } - - bool bad = cfgFile.bad(); - cfgFile.close(); - - if( bad ) - { - wxMessageBox( _( "Problems writing configuration file" ), - _( "Write 3D search path list" ) ); - - return false; - } - - return true; -} - - void FILENAME_RESOLVER::checkEnvVarPath( const wxString& aPath ) { bool useParen = false; diff --git a/include/filename_resolver.h b/include/filename_resolver.h index 7d8febdcfc..4570f60215 100644 --- a/include/filename_resolver.h +++ b/include/filename_resolver.h @@ -34,6 +34,7 @@ #include #include +class PROJECT; class PGM_BASE; struct SEARCH_PATH @@ -89,12 +90,6 @@ public: */ bool UpdatePathList( const std::vector& aPathList ); - /** - * Write the current path list to a config file. - * @param aResolvePaths indicates whether env vars should also be written out or not - */ - bool WritePathList( const wxString& aDir, const wxString& aFilename, bool aResolvePaths ); - /** * Determines the full path of the given file name. * diff --git a/pcbnew/dialogs/dialog_export_step.cpp b/pcbnew/dialogs/dialog_export_step.cpp index 48e421326d..56e79ba3e6 100644 --- a/pcbnew/dialogs/dialog_export_step.cpp +++ b/pcbnew/dialogs/dialog_export_step.cpp @@ -363,11 +363,6 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent ) return; } - FILENAME_RESOLVER* fnResolver = m_parent->Prj().Get3DFilenameResolver(); - - fnResolver->WritePathList( wxStandardPaths::Get().GetTempDir(), wxT( "ExportPaths.cfg" ), - true ); - DIALOG_EXPORT_STEP::STEP_ORG_OPT orgOpt = GetOriginOption(); double xOrg = 0.0; double yOrg = 0.0; diff --git a/pcbnew/exporters/step/CMakeLists.txt b/pcbnew/exporters/step/CMakeLists.txt index 1f4f4b9e5b..8d01797291 100644 --- a/pcbnew/exporters/step/CMakeLists.txt +++ b/pcbnew/exporters/step/CMakeLists.txt @@ -5,7 +5,7 @@ include_directories( SYSTEM set( KS2_LIB_FILES kicad2step.cpp - pcb/3d_resolver.cpp + pcb/base.cpp pcb/kicadmodel.cpp pcb/kicadfootprint.cpp diff --git a/pcbnew/exporters/step/pcb/3d_resolver.cpp b/pcbnew/exporters/step/pcb/3d_resolver.cpp deleted file mode 100644 index 20d21d9200..0000000000 --- a/pcbnew/exporters/step/pcb/3d_resolver.cpp +++ /dev/null @@ -1,797 +0,0 @@ -/* - * This program source code file is part kicad2mcad - * - * Copyright (C) 2015-2016 Cirilo Bernardo - * Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "3d_resolver.h" - -// configuration file version -#define CFGFILE_VERSION 1 -#define S3D_RESOLVER_CONFIG "ExportPaths.cfg" - -// flag bits used to track different one-off messages to users -#define ERRFLG_ALIAS (1) -#define ERRFLG_RELPATH (2) -#define ERRFLG_ENVPATH (4) - - -/** - * Flag to enable plugin loader trace output. - * - * @ingroup trace_env_vars - */ -const wxChar* const trace3dResolver = wxT( "KICAD_3D_RESOLVER" ); - - -static std::mutex mutex3D_resolver; - - -static bool getHollerith( const std::string& aString, size_t& aIndex, wxString& aResult ); - - -S3D_RESOLVER::S3D_RESOLVER() -{ - m_errflags = 0; -} - - -bool S3D_RESOLVER::Set3DConfigDir( const wxString& aConfigDir ) -{ - createPathList(); - - return true; -} - - -bool S3D_RESOLVER::createPathList( void ) -{ - if( !m_Paths.empty() ) - return true; - - readPathList(); - - if( m_Paths.empty() ) - return false; - -#ifdef DEBUG - wxLogTrace( trace3dResolver, wxT( " * [3D model] search paths:\n" ) ); - - for( const SEARCH_PATH& searchPath : m_Paths ) - wxLogTrace( trace3dResolver, wxT( " + '%s'\n" ), searchPath.m_Pathexp ); -#endif - - return true; -} - - -wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName, - std::vector& aSearchedPaths ) -{ - std::lock_guard lock( mutex3D_resolver ); - - if( aFileName.empty() ) - return wxEmptyString; - - if( m_Paths.empty() ) - createPathList(); - - // look up the filename in the internal filename map - std::map::iterator mi; - mi = m_NameMap.find( aFileName ); - - if( mi != m_NameMap.end() ) - return mi->second; - - // first attempt to use the name as specified: - wxString tname = aFileName; - -#ifdef _WIN32 - // translate from KiCad's internal UNIX-like path to MSWin paths - tname.Replace( wxT( "/" ), wxT( "\\" ) ); -#endif - - // Note: variable expansion must preferably be performed via a threadsafe wrapper for the - // getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion - // then we will have a race condition since wxWidgets does not assure a threadsafe wrapper - // for getenv(). - if( tname.StartsWith( wxT( "${" ) ) || tname.StartsWith( wxT( "$(" ) ) ) - tname = expandVars( tname ); - - wxFileName tmpFN( tname ); - - // in the case of absolute filenames we don't store a map item - if( !aFileName.StartsWith( wxT( "${" ) ) && !aFileName.StartsWith( wxT( "$(" ) ) - && tmpFN.IsAbsolute() ) - { - if( tmpFN.FileExists() ) - { - tmpFN.Normalize( FN_NORMALIZE_FLAGS ); - return tmpFN.GetFullPath(); - } - else - { - aSearchedPaths.push_back( tmpFN.GetFullPath() ); - } - } - - // this case covers full paths, leading expanded vars, and paths relative to the current - // working directory (which is not necessarily the current project directory) - tmpFN.Normalize( FN_NORMALIZE_FLAGS ); - - if( tmpFN.FileExists() ) - { - tname = tmpFN.GetFullPath(); - m_NameMap[ aFileName ] = tname; - - // special case: if a path begins with ${ENV_VAR} but is not in the resolver's path list - // then add it - if( aFileName.StartsWith( wxT( "${" ) ) || aFileName.StartsWith( wxT( "$(" ) ) ) - checkEnvVarPath( aFileName ); - - return tname; - } - else if( tmpFN.GetFullPath() != aFileName ) - { - aSearchedPaths.push_back( tmpFN.GetFullPath() ); - } - - // if a path begins with ${ENV_VAR}/$(ENV_VAR) and is not resolved then the file either does - // not exist or the ENV_VAR is not defined - if( aFileName.StartsWith( wxT( "${" ) ) || aFileName.StartsWith( wxT( "$(" ) ) ) - { - m_errflags |= ERRFLG_ENVPATH; - return aFileName; - } - - // at this point aFileName is: - // a. an aliased shortened name or - // b. cannot be determined - - // check the path relative to the current project directory; - // NB: this is not necessarily the same as the current working directory, which has already - // been checked. This case accounts for partial paths which do not contain ${KIPRJMOD}. - // This check is performed before checking the path relative to ${KICAD6_3DMODEL_DIR} so that - // users can potentially override a model within ${KICAD6_3DMODEL_DIR}. - if( !m_Paths.empty() && !m_Paths.begin()->m_Pathexp.empty() && !tname.StartsWith( wxT( ":" ) ) ) - { - tmpFN.Assign( m_Paths.begin()->m_Pathexp, wxT( "" ) ); - wxString fullPath = tmpFN.GetPathWithSep() + tname; - - if( fullPath.StartsWith( wxT( "${" ) ) || fullPath.StartsWith( wxT( "$(" ) ) ) - fullPath = expandVars( fullPath ); - - tmpFN.Assign( fullPath ); - tmpFN.Normalize( FN_NORMALIZE_FLAGS ); - - if( tmpFN.FileExists() ) - { - tname = tmpFN.GetFullPath(); - m_NameMap[ aFileName ] = tname; - return tname; - } - else if( tmpFN.GetFullPath() != aFileName ) - { - aSearchedPaths.push_back( tmpFN.GetFullPath() ); - } - } - - // check the partial path relative to ${KICAD6_3DMODEL_DIR} (legacy behavior) - if( !tname.Contains( wxT( ":" ) ) ) - { - wxFileName fpath; - wxString fullPath( wxT( "${KICAD6_3DMODEL_DIR}" ) ); - fullPath.Append( fpath.GetPathSeparator() ); - fullPath.Append( tname ); - fullPath = expandVars( fullPath ); - fpath.Assign( fullPath ); - fpath.Normalize( FN_NORMALIZE_FLAGS ); - - if( fpath.FileExists() ) - { - tname = fpath.GetFullPath(); - m_NameMap[ aFileName ] = tname; - return tname; - } - else - { - aSearchedPaths.push_back( fpath.GetFullPath() ); - } - } - - // at this point the filename must contain an alias or else it is invalid - wxString alias; // the alias portion of the short filename - wxString relpath; // the path relative to the alias - - if( !SplitAlias( tname, alias, relpath ) ) - { - // this can happen if the file was intended to be relative to ${KICAD6_3DMODEL_DIR} - // but ${KICAD6_3DMODEL_DIR} is not set or is incorrect. - m_errflags |= ERRFLG_RELPATH; - return aFileName; - } - - for( const SEARCH_PATH& path : m_Paths ) - { - // ${ENV_VAR} paths have already been checked; skip them - if( path.m_Alias.StartsWith( wxT( "${" ) ) || path.m_Alias.StartsWith( wxT( "$(" ) ) ) - continue; - - if( path.m_Alias == alias && !path.m_Pathexp.empty() ) - { - wxFileName fpath( wxFileName::DirName( path.m_Pathexp ) ); - wxString fullPath = fpath.GetPathWithSep() + relpath; - - if( fullPath.StartsWith( wxT( "${" ) ) || fullPath.StartsWith( wxT( "$(" ) ) ) - fullPath = expandVars( fullPath ); - - wxFileName tmp( fullPath ); - tmp.Normalize( FN_NORMALIZE_FLAGS ); - - if( tmp.FileExists() ) - { - tname = tmp.GetFullPath(); - m_NameMap[ aFileName ] = tname; - return tname; - } - else - { - aSearchedPaths.push_back( tmp.GetFullPath() ); - } - } - } - - m_errflags |= ERRFLG_ALIAS; - return aFileName; -} - - -bool S3D_RESOLVER::addPath( const SEARCH_PATH& aPath ) -{ - if( aPath.m_Alias.empty() || aPath.m_Pathvar.empty() ) - return false; - - std::lock_guard lock( mutex3D_resolver ); - - SEARCH_PATH tpath = aPath; - -#ifdef _WIN32 - while( tpath.m_Pathvar.EndsWith( wxT( "\\" ) ) ) - tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 ); -#else - while( tpath.m_Pathvar.EndsWith( wxT( "/" ) ) && tpath.m_Pathvar.length() > 1 ) - tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 ); -#endif - - wxFileName path( tpath.m_Pathvar, wxT( "" ) ); - path.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ); - - if( !path.DirExists() ) - { - // Show a message only in debug mode -#ifdef DEBUG - if( aPath.m_Pathvar == wxT( "${KICAD6_3DMODEL_DIR}" ) - || aPath.m_Pathvar == wxT( "${KIPRJMOD}" ) - || aPath.m_Pathvar == wxT( "${KISYS3DMOD}" ) ) - { - // suppress the message if the missing pathvar is a system variable - } - else - { - wxString msg = _( "The given path does not exist" ); - msg.append( wxT( "\n" ) ); - msg.append( tpath.m_Pathvar ); - wxLogMessage( wxT( "%s\n" ), msg.ToUTF8() ); - } -#endif - - tpath.m_Pathexp.clear(); - } - else - { - tpath.m_Pathexp = path.GetFullPath(); - -#ifdef _WIN32 - while( tpath.m_Pathexp.EndsWith( wxT( "\\" ) ) ) - tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 ); -#else - while( tpath.m_Pathexp.EndsWith( wxT( "/" ) ) && tpath.m_Pathexp.length() > 1 ) - tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 ); -#endif - } - - std::list< SEARCH_PATH >::iterator sPL = m_Paths.begin(); - std::list< SEARCH_PATH >::iterator ePL = m_Paths.end(); - - while( sPL != ePL ) - { - if( tpath.m_Alias == sPL->m_Alias ) - { - wxString msg = _( "Alias:" ) + wxS( " " ); - msg.append( tpath.m_Alias ); - msg.append( wxS( "\n" ) ); - msg.append( _( "This path:" ) + wxS( " " ) ); - msg.append( tpath.m_Pathvar ); - msg.append( wxS( "\n" ) ); - msg.append( _( "Existing path:" ) + wxS( " " ) ); - msg.append( sPL->m_Pathvar ); - wxMessageBox( msg, _( "Bad alias (duplicate name)" ) ); - - return false; - } - - ++sPL; - } - - m_Paths.push_back( tpath ); - return true; -} - - -bool S3D_RESOLVER::readPathList( void ) -{ - wxFileName cfgpath( wxStandardPaths::Get().GetTempDir(), S3D_RESOLVER_CONFIG ); - cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ); - wxString cfgname = cfgpath.GetFullPath(); - - size_t nitems = m_Paths.size(); - - std::ifstream cfgFile; - std::string cfgLine; - - if( !wxFileName::Exists( cfgname ) ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * no 3D configuration file '%s'" ), - __FILE__, __FUNCTION__, __LINE__, cfgname ); - - return false; - } - - cfgFile.open( cfgname.ToUTF8() ); - - if( !cfgFile.is_open() ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * Could not open configuration file '%s'" ), - __FILE__, __FUNCTION__, __LINE__, cfgname ); - - return false; - } - - int lineno = 0; - SEARCH_PATH al; - size_t idx; - int vnum = 0; // version number - - while( cfgFile.good() ) - { - cfgLine.clear(); - std::getline( cfgFile, cfgLine ); - ++lineno; - - if( cfgLine.empty() ) - { - if( cfgFile.eof() ) - break; - - continue; - } - - if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 ) - { - // extract the version number and parse accordingly - if( cfgLine.size() > 2 ) - { - std::istringstream istr; - istr.str( cfgLine.substr( 2 ) ); - istr >> vnum; - } - - continue; - } - - idx = 0; - - if( !getHollerith( cfgLine, idx, al.m_Alias ) ) - continue; - - if( !getHollerith( cfgLine, idx, al.m_Pathvar ) ) - continue; - - if( !getHollerith( cfgLine, idx, al.m_Description ) ) - continue; - - addPath( al ); - } - - cfgFile.close(); - - if( m_Paths.size() != nitems ) - return true; - - return false; -} - - -void S3D_RESOLVER::checkEnvVarPath( const wxString& aPath ) -{ - bool useParen = false; - - if( aPath.StartsWith( wxT( "$(" ) ) ) - useParen = true; - else if( !aPath.StartsWith( wxT( "${" ) ) ) - return; - - size_t pEnd; - - if( useParen ) - pEnd = aPath.find( wxT( ")" ) ); - else - pEnd = aPath.find( wxT( "}" ) ); - - if( pEnd == wxString::npos ) - return; - - wxString envar = aPath.substr( 0, pEnd + 1 ); - - // check if the alias exists; if not then add it to the end of the - // env var section of the path list - std::list< SEARCH_PATH >::iterator sPL = m_Paths.begin(); - std::list< SEARCH_PATH >::iterator ePL = m_Paths.end(); - - while( sPL != ePL ) - { - if( sPL->m_Alias == envar ) - return; - - if( !sPL->m_Alias.StartsWith( wxT( "${" ) ) ) - break; - - ++sPL; - } - - SEARCH_PATH lpath; - lpath.m_Alias = envar; - lpath.m_Pathvar = lpath.m_Alias; - wxFileName tmpFN( lpath.m_Alias, wxT( "" ) ); - wxUniChar psep = tmpFN.GetPathSeparator(); - tmpFN.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ); - - if( !tmpFN.DirExists() ) - return; - - lpath.m_Pathexp = tmpFN.GetFullPath(); - - if( !lpath.m_Pathexp.empty() && psep == *lpath.m_Pathexp.rbegin() ) - lpath.m_Pathexp.erase( --lpath.m_Pathexp.end() ); - - if( lpath.m_Pathexp.empty() ) - return; - - m_Paths.insert( sPL, lpath ); - return; -} - - -wxString S3D_RESOLVER::expandVars( const wxString& aPath ) -{ - if( aPath.empty() ) - return wxEmptyString; - - wxString result; - - for( const std::pair& i : m_EnvVars ) - { - if( !aPath.compare( 2, i.first.length(), i.first ) ) - { - result = i.second; - result.append( aPath.substr( 3 + i.first.length() ) ); - - if( result.StartsWith( wxT( "${" ) ) || result.StartsWith( wxT( "$(" ) ) ) - result = expandVars( result ); - - return result; - } - } - - result = wxExpandEnvVars( aPath ); - - if( result == aPath ) - return wxEmptyString; - - if( result.StartsWith( wxT( "${" ) ) || result.StartsWith( wxT( "$(" ) ) ) - result = expandVars( result ); - - return result; -} - - -wxString S3D_RESOLVER::ShortenPath( const wxString& aFullPathName ) -{ - wxString fname = aFullPathName; - - if( m_Paths.empty() ) - createPathList(); - - std::lock_guard lock( mutex3D_resolver ); - - std::list< SEARCH_PATH >::const_iterator sL = m_Paths.begin(); - std::list< SEARCH_PATH >::const_iterator eL = m_Paths.end(); - size_t idx; - - while( sL != eL ) - { - // undefined paths do not participate in the file name shortening procedure. - if( sL->m_Pathexp.empty() ) - { - ++sL; - continue; - } - - wxFileName fpath( sL->m_Pathexp, wxT( "" ) ); - wxString fps = fpath.GetPathWithSep(); - wxString tname; - - idx = fname.find( fps ); - - if( std::string::npos != idx && 0 == idx ) - { - fname = fname.substr( fps.size() ); - -#ifdef _WIN32 - // ensure only the '/' separator is used in the internal name - fname.Replace( wxT( "\\" ), wxT( "/" ) ); -#endif - - if( sL->m_Alias.StartsWith( wxT( "${" ) ) || sL->m_Alias.StartsWith( wxT( "$(" ) ) ) - { - // old style ENV_VAR - tname = sL->m_Alias; - tname.Append( wxT( "/" ) ); - tname.append( fname ); - } - else - { - // new style alias - tname = wxT( ":" ); - tname.append( sL->m_Alias ); - tname.append( wxT( ":" ) ); - tname.append( fname ); - } - - return tname; - } - - ++sL; - } - -#ifdef _WIN32 - // it is strange to convert an MSWin full path to use the - // UNIX separator but this is done for consistency and can - // be helpful even when transferring project files from - // MSWin to *NIX. - fname.Replace( wxT( "\\" ), wxT( "/" ) ); -#endif - - return fname; -} - - -const std::list< SEARCH_PATH >* S3D_RESOLVER::GetPaths( void ) -{ - return &m_Paths; -} - - -bool S3D_RESOLVER::SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath ) -{ - anAlias.clear(); - aRelPath.clear(); - - size_t searchStart = 0; - - if( aFileName.StartsWith( wxT( ":" ) ) ) - searchStart = 1; - - size_t tagpos = aFileName.find( wxT( ":" ), searchStart ); - - if( tagpos == wxString::npos || tagpos == searchStart ) - return false; - - if( tagpos + 1 >= aFileName.length() ) - return false; - - anAlias = aFileName.substr( searchStart, tagpos - searchStart ); - aRelPath = aFileName.substr( tagpos + 1 ); - - return true; -} - - -static bool getHollerith( const std::string& aString, size_t& aIndex, wxString& aResult ) -{ - aResult.clear(); - - if( aIndex >= aString.size() ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * Bad Hollerith string in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - size_t i2 = aString.find( '"', aIndex ); - - if( std::string::npos == i2 ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * missing opening quote mark in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - ++i2; - - if( i2 >= aString.size() ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * unexpected end of line in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - std::string tnum; - - while( aString[i2] >= '0' && aString[i2] <= '9' ) - tnum.append( 1, aString[i2++] ); - - if( tnum.empty() || aString[i2++] != ':' ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * Bad Hollerith string in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - std::istringstream istr; - istr.str( tnum ); - size_t nchars; - istr >> nchars; - - if( ( i2 + nchars ) >= aString.size() ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * unexpected end of line in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - if( nchars > 0 ) - { - aResult = wxString::FromUTF8( aString.substr( i2, nchars ).c_str() ); - i2 += nchars; - } - - if( i2 >= aString.size() || aString[i2] != '"' ) - { - wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n * missing closing quote mark in line '%s'" ), - __FILE__, __FUNCTION__, __LINE__, aString ); - - return false; - } - - aIndex = i2 + 1; - return true; -} - - -bool S3D_RESOLVER::ValidateFileName( const wxString& aFileName, bool& hasAlias ) -{ - // Rules: - // 1. The generic form of an aliased 3D relative path is: - // ALIAS:relative/path - // 2. ALIAS is a UTF string excluding "{}[]()%~<>\"='`;:.,&?/\\|$" - // 3. The relative path must be a valid relative path for the platform - hasAlias = false; - - if( aFileName.empty() ) - return false; - - wxString filename = aFileName; - wxString lpath; - size_t aliasStart = aFileName.StartsWith( ':' ) ? 1 : 0; - size_t aliasEnd = aFileName.find( ':' ); - - // ensure that the file separators suit the current platform -#ifdef __WINDOWS__ - filename.Replace( wxT( "/" ), wxT( "\\" ) ); - - // if we see the :\ pattern then it must be a drive designator - if( aliasEnd != wxString::npos ) - { - size_t pos1 = aFileName.find( wxT( ":\\" ) ); - - if( pos1 != wxString::npos && ( pos1 != aliasEnd || pos1 != 1 ) ) - return false; - - // if we have a drive designator then we have no alias - if( pos1 != wxString::npos ) - aliasEnd = wxString::npos; - } -#else - filename.Replace( wxT( "\\" ), wxT( "/" ) ); -#endif - - // names may not end with ':' - if( aliasEnd == aFileName.length() - 1 ) - return false; - - if( aliasEnd != wxString::npos ) - { - // ensure the alias component is not empty - if( aliasEnd == aliasStart ) - return false; - - lpath = filename.substr( aliasStart, aliasEnd ); - - // check the alias for restricted characters - if( wxString::npos != lpath.find_first_of( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) - return false; - - hasAlias = true; - lpath = aFileName.substr( aliasEnd + 1 ); - } - else - { - lpath = aFileName; - - // in the case of ${ENV_VAR}|$(ENV_VAR)/path, strip the - // environment string before testing - aliasEnd = wxString::npos; - - if( aFileName.StartsWith( wxT( "${" ) ) ) - aliasEnd = aFileName.find( '}' ); - else if( aFileName.StartsWith( wxT( "$(" ) ) ) - aliasEnd = aFileName.find( ')' ); - - if( aliasEnd != wxString::npos ) - lpath = aFileName.substr( aliasEnd + 1 ); - } - - if( wxString::npos != lpath.find_first_of( wxFileName::GetForbiddenChars() ) ) - return false; - - return true; -} diff --git a/pcbnew/exporters/step/pcb/3d_resolver.h b/pcbnew/exporters/step/pcb/3d_resolver.h deleted file mode 100644 index fd3c010032..0000000000 --- a/pcbnew/exporters/step/pcb/3d_resolver.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2015-2016 Cirilo Bernardo - * Copyright (C) 2021 KiCad Developers, see AUTHORS.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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file 3d_resolver.h - * provides an extensible class to resolve 3D model paths. - * Derived from 3d_filename_resolver.h,cpp and modified for - * use in stand-alone utilities. - */ - -#ifndef RESOLVER_3D_H -#define RESOLVER_3D_H - -#include -#include -#include -#include - -namespace S3D -{ -struct rsort_wxString -{ - bool operator() (const wxString& strA, const wxString& strB ) const - { - // sort a wxString using the reverse character order; for 3d model - // filenames this will typically be a much faster operation than - // a normal alphabetic sort - wxString::const_reverse_iterator sA = strA.rbegin(); - wxString::const_reverse_iterator eA = strA.rend(); - - wxString::const_reverse_iterator sB = strB.rbegin(); - wxString::const_reverse_iterator eB = strB.rend(); - - if( strA.empty() ) - { - if( strB.empty() ) - return false; - - // note: this rule implies that a null string is first in the sort order - return true; - } - - if( strB.empty() ) - return false; - - while( sA != eA && sB != eB ) - { - if( (*sA) == (*sB) ) - { - ++sA; - ++sB; - continue; - } - - if( (*sA) < (*sB) ) - return true; - else - return false; - } - - if( sB == eB ) - return false; - - return true; - } -}; - -}; // end NAMESPACE - - -class KICADPCB; - -struct SEARCH_PATH -{ - wxString m_Alias; // alias to the base path - wxString m_Pathvar; // base path as stored in the config file - wxString m_Pathexp; // expanded base path - wxString m_Description; // description of the aliased path -}; - - -class S3D_RESOLVER -{ -public: - S3D_RESOLVER(); - - /** - * Set the user's configuration directory for 3D models. - * - * @param aConfigDir - * @return true if the call succeeds (directory exists). - */ - bool Set3DConfigDir( const wxString& aConfigDir ); - - /** - * Determine the full path of the given file name. - * - * In the future remote files may be supported, in which case it is best to require a full - * URI in which case #ResolvePath should check that the URI conforms to RFC-2396 and related - * documents and copies \a aFileName into the resolved name if the URI is valid. - * - * If the file is not found, \a aSearchedPaths will contain the paths that were searched. - */ - wxString ResolvePath( const wxString& aFileName, std::vector& aSearchedPaths ); - - /** - * Produce a relative path based on the existing search directories or returns the same path - * if the path is not a superset of an existing search path. - * - * @param aFullPathName is an absolute path to shorten. - * @return the shortened path or aFullPathName. - */ - wxString ShortenPath( const wxString& aFullPathName ); - - /** - * Return a pointer to the internal path list. - * - * The list can be used to set up the list of search paths available to a 3D file browser. - * - * @return the search path list. - */ - const std::list< SEARCH_PATH >* GetPaths( void ); - - /** - * Return true if the given name contains an alias and populates the string with the alias - * and the relative path. - */ - bool SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath ); - - /** - * If the path contains an alias then \a hasAlias is set true. - * - * @return true if the given path is a valid aliased relative path. - */ - bool ValidateFileName( const wxString& aFileName, bool& hasAlias ); - -private: - /** - * Build the path list using available information such as KICAD6_3DMODEL_DIR and the - * 3d_path_list configuration file. - * - * Invalid paths are silently discarded and removed from the configuration file. - * - * @return true if at least one valid path was found - */ - bool createPathList( void ); - - /** - * Check that \a aPath is valid and adds it to the search list. - * - * @param aPath is the alias set to be checked and added. - * @return true if \a aPath is valid. - */ - bool addPath( const SEARCH_PATH& aPath ); - - /** - * Read a list of path names from a configuration file. - * - * @return true if a file was found and contained at least one valid path. - */ - bool readPathList( void ); - - /** - * Check the ${ENV_VAR} component of a path and adds it to the resolver's path list if it - * is not yet in the list. - */ - void checkEnvVarPath( const wxString& aPath ); - - wxString expandVars( const wxString& aPath ); - - std::list< SEARCH_PATH > m_Paths; ///< List of base search paths. - - ///< Mapping of (short) file names to resolved names. - std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap; - int m_errflags; - wxString m_curProjDir; - - ///< Environment variables. - std::map< wxString, wxString > m_EnvVars; -}; - -#endif // RESOLVER_3D_H diff --git a/pcbnew/exporters/step/pcb/kicadfootprint.cpp b/pcbnew/exporters/step/pcb/kicadfootprint.cpp index 222b4b00a0..ac596daf4a 100644 --- a/pcbnew/exporters/step/pcb/kicadfootprint.cpp +++ b/pcbnew/exporters/step/pcb/kicadfootprint.cpp @@ -24,7 +24,7 @@ #include "kicadfootprint.h" -#include "3d_resolver.h" +#include #include "kicadcurve.h" #include "kicadmodel.h" #include "kicadpad.h" @@ -358,7 +358,7 @@ bool KICADFOOTPRINT::parsePad( SEXPR::SEXPR* data ) } -bool KICADFOOTPRINT::ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver, +bool KICADFOOTPRINT::ComposePCB( class PCBMODEL* aPCB, FILENAME_RESOLVER* resolver, DOUBLET aOrigin, bool aComposeVirtual, bool aSubstituteModels ) { // translate pads and curves to final position and append to PCB. @@ -439,22 +439,14 @@ bool KICADFOOTPRINT::ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver, continue; std::vector searchedPaths; - mname = resolver->ResolvePath( mname, searchedPaths ); + mname = resolver->ResolvePath( mname, wxEmptyString ); if( !wxFileName::FileExists( mname ) ) { - wxString paths; - - for( const wxString& path : searchedPaths ) - paths += " " + path + "\n"; - ReportMessage( wxString::Format( wxT( "Could not add 3D model to %s.\n" - "File not found: %s\n" - "Searched paths:\n" - "%s" ), + "File not found: %s\n" ), m_refdes, - mname, - paths) ); + mname) ); continue; } diff --git a/pcbnew/exporters/step/pcb/kicadfootprint.h b/pcbnew/exporters/step/pcb/kicadfootprint.h index e0810f9c20..c6618e68c1 100644 --- a/pcbnew/exporters/step/pcb/kicadfootprint.h +++ b/pcbnew/exporters/step/pcb/kicadfootprint.h @@ -40,7 +40,7 @@ class KICADPAD; class KICADCURVE; class KICADMODEL; class PCBMODEL; -class S3D_RESOLVER; +class FILENAME_RESOLVER; class KICADFOOTPRINT { @@ -50,7 +50,7 @@ public: bool Read( SEXPR::SEXPR* aEntry ); - bool ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver, + bool ComposePCB( class PCBMODEL* aPCB, FILENAME_RESOLVER* resolver, DOUBLET aOrigin, bool aComposeVirtual = true, bool aSubstituteModels = true ); private: diff --git a/pcbnew/exporters/step/pcb/kicadpcb.h b/pcbnew/exporters/step/pcb/kicadpcb.h index 08669b6dba..8f40237b97 100644 --- a/pcbnew/exporters/step/pcb/kicadpcb.h +++ b/pcbnew/exporters/step/pcb/kicadpcb.h @@ -34,7 +34,7 @@ #include #include #include -#include "3d_resolver.h" +#include #include "base.h" #ifdef SUPPORTS_IGES @@ -102,7 +102,7 @@ private: bool parsePolygon( SEXPR::SEXPR* data ); private: - S3D_RESOLVER m_resolver; + FILENAME_RESOLVER m_resolver; wxString m_filename; PCBMODEL* m_pcb_model; DOUBLET m_origin;