wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName ) { wxCriticalSectionLocker lock( lock3D_resolver ); if( aFileName.empty() ) return wxEmptyString; if( m_Paths.empty() ) createPathList(); // 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 be performed using 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( "${" ) || tname.StartsWith( "$(" ) ) tname = ExpandEnvVarSubstitutions( tname ); wxFileName tmpFN( tname ); // in the case of absolute filenames we don't store a map item if( !aFileName.StartsWith( "${" ) && !aFileName.StartsWith( "$(" ) && !aFileName.StartsWith( ":" ) && tmpFN.IsAbsolute() ) { tmpFN.Normalize(); if( tmpFN.FileExists() ) return tmpFN.GetFullPath(); return wxEmptyString; } // this case covers full paths, leading expanded vars, and paths // relative to the current working directory (which is not necessarily // the current project directory) if( tmpFN.FileExists() ) { tmpFN.Normalize(); tname = tmpFN.GetFullPath(); // special case: if a path begins with ${ENV_VAR} but is not in the // resolver's path list then add it. if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) ) checkEnvVarPath( aFileName ); return tname; } // 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( "${" ) || aFileName.StartsWith( "$(" ) ) { if( !( m_errflags & ERRFLG_ENVPATH ) ) { m_errflags |= ERRFLG_ENVPATH; wxString errmsg = "[3D File Resolver] No such path; ensure the environment var is defined"; errmsg.append( "\n" ); errmsg.append( tname ); wxLogMessage( errmsg ); } return wxEmptyString; } // at this point aFileName is: // a. an aliased shortened name or // b. cannot be determined std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin(); std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end(); // check the path relative to the current project directory; // note: 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 // ${KISYS3DMOD} so that users can potentially override a model // within ${KISYS3DMOD} if( !sPL->m_pathexp.empty() && !tname.StartsWith( ":" ) ) { tmpFN.Assign( sPL->m_pathexp, "" ); wxString fullPath = tmpFN.GetPathWithSep() + tname; if( fullPath.StartsWith( "${" ) || fullPath.StartsWith( "$(" ) ) fullPath = ExpandEnvVarSubstitutions( fullPath ); if( wxFileName::FileExists( fullPath ) ) { tmpFN.Assign( fullPath ); tmpFN.Normalize(); tname = tmpFN.GetFullPath(); return tname; } } // check the partial path relative to ${KISYS3DMOD} (legacy behavior) if( !tname.StartsWith( ":" ) ) { wxFileName fpath; wxString fullPath( "${KISYS3DMOD}" ); fullPath.Append( fpath.GetPathSeparator() ); fullPath.Append( tname ); fullPath = ExpandEnvVarSubstitutions( fullPath ); fpath.Assign( fullPath ); if( fpath.Normalize() && fpath.FileExists() ) { tname = fpath.GetFullPath(); return tname; } } // ${ENV_VAR} paths have already been checked; skip them while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" ) || sPL->m_alias.StartsWith( "$(" ) ) ) ++sPL; // 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 ) ) { if( !( m_errflags & ERRFLG_RELPATH ) ) { // this can happen if the file was intended to be relative to // ${KISYS3DMOD} but ${KISYS3DMOD} not set or incorrect. m_errflags |= ERRFLG_RELPATH; wxString errmsg = "[3D File Resolver] No such path"; errmsg.append( "\n" ); errmsg.append( tname ); wxLogTrace( MASK_3D_RESOLVER, errmsg ); } return wxEmptyString; } while( sPL != ePL ) { if( !sPL->m_alias.Cmp( alias ) && !sPL->m_pathexp.empty() ) { wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxString fullPath = fpath.GetPathWithSep() + relpath; if( fullPath.StartsWith( "${") || fullPath.StartsWith( "$(" ) ) fullPath = ExpandEnvVarSubstitutions( fullPath ); if( wxFileName::FileExists( fullPath ) ) { wxFileName tmp( fullPath ); if( tmp.Normalize() ) tname = tmp.GetFullPath(); return tname; } } ++sPL; } if( !( m_errflags & ERRFLG_ALIAS ) ) { m_errflags |= ERRFLG_ALIAS; wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined"; errmsg.append( "\n" ); errmsg.append( tname.substr( 1 ) ); wxLogTrace( MASK_3D_RESOLVER, errmsg ); } return wxEmptyString; }
wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName ) { wxCriticalSectionLocker lock( lock3D_resolver ); if( aFileName.empty() ) return wxEmptyString; if( m_Paths.empty() ) createPathList(); // look up the filename in the internal filename map std::map< wxString, wxString, S3D::rsort_wxString >::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 // this case covers full paths and paths relative to // the current working directory (which is not necessarily // the current project directory) if( wxFileName::FileExists( tname ) ) { wxFileName tmp( tname ); if( tmp.Normalize() ) tname = tmp.GetFullPath(); m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } // at this point aFileName: // a. is a legacy ${} shortened name // b. an aliased shortened name // c. cannot be determined if( aFileName.StartsWith( wxT( "${" ) ) ) { wxFileName tmp( aFileName ); if( tmp.Normalize() ) { tname = tmp.GetFullPath(); m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } else if( resolveVirtualEnv( aFileName, tname ) ) { m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } if( !( m_errflags & ERRFLG_ENVPATH ) ) { m_errflags |= ERRFLG_ENVPATH; wxString errmsg = _( "[3D File Resolver] No such path; ensure the environment var is defined" ); errmsg.append( "\n" ); errmsg.append( tname ); wxLogMessage( "%s\n", errmsg.ToUTF8() ); } return wxEmptyString; } std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin(); std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end(); // check the path relative to the current project directory; // note: 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}. if( !sPL->m_pathexp.empty() ) { wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxString fullPath = fpath.GetPathWithSep() + tname; if( wxFileName::FileExists( fullPath ) ) { wxFileName tmp( fullPath ); if( tmp.Normalize() ) tname = tmp.GetFullPath(); m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } } // ${ENV_VAR} paths have already been checked; skip all but // ${KISYS3DMOD}, since legacy behavior was to check if paths // were relative to ${KISYS3DMOD} while( sPL != ePL && sPL->m_alias.StartsWith( "${" ) ) { if( sPL->m_alias == "${KISYS3DMOD}" ) { wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxString fullPath = fpath.GetPathWithSep() + tname; if( wxFileName::FileExists( fullPath ) ) { wxFileName tmp( fullPath ); if( tmp.Normalize() ) tname = tmp.GetFullPath(); m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } } ++sPL; } // 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 ) ) { if( !( m_errflags & ERRFLG_RELPATH ) ) { // this can happen if the file was intended to be relative to // ${KISYS3DMOD} but ${KISYS3DMOD} not set or incorrect. m_errflags |= ERRFLG_RELPATH; wxString errmsg = _( "[3D File Resolver] No such path" ); errmsg.append( "\n" ); errmsg.append( tname ); wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() ); } return wxEmptyString; } while( sPL != ePL ) { if( !sPL->m_alias.Cmp( alias ) && !sPL->m_pathexp.empty() ) { wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxString fullPath = fpath.GetPathWithSep() + relpath; if( wxFileName::FileExists( fullPath ) ) { wxFileName tmp( fullPath ); if( tmp.Normalize() ) tname = tmp.GetFullPath(); m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) ); return tname; } } ++sPL; } if( !( m_errflags & ERRFLG_ALIAS ) ) { m_errflags |= ERRFLG_ALIAS; wxString errmsg = _( "[3D File Resolver] No such path; ensure the path alias is defined" ); errmsg.append( "\n" ); errmsg.append( tname.substr( 1 ) ); wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() ); } return wxEmptyString; }