KiCad PCB EDA Suite
FILENAME_RESOLVER Class Reference

Provide an extensible class to resolve 3D model paths. More...

#include <filename_resolver.h>

Public Member Functions

 FILENAME_RESOLVER ()
 
bool Set3DConfigDir (const wxString &aConfigDir)
 Set the user's configuration directory for 3D models. More...
 
bool SetProject (PROJECT *aProject, bool *flgChanged=nullptr)
 Set the current KiCad project directory as the first entry in the model path list. More...
 
wxString GetProjectDir () const
 
void SetProgramBase (PGM_BASE *aBase)
 Set a pointer to the application's PGM_BASE instance used to extract the local env vars. More...
 
bool UpdatePathList (const std::vector< SEARCH_PATH > &aPathList)
 Clear the current path list and substitutes the given path list and update the path configuration file on success. More...
 
wxString ResolvePath (const wxString &aFileName, const wxString &aWorkingPath)
 Determines the full path of the given file name. More...
 
wxString ShortenPath (const wxString &aFullPathName)
 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. More...
 
const std::list< SEARCH_PATH > * GetPaths () const
 Return a pointer to the internal path list; the items in:load. More...
 
bool SplitAlias (const wxString &aFileName, wxString &anAlias, wxString &aRelPath) const
 Return true if the given name contains an alias and populates the string anAlias with the alias and aRelPath with the relative path. More...
 
bool ValidateFileName (const wxString &aFileName, bool &hasAlias) const
 Returns true if the given path is a valid aliased relative path. More...
 
bool GetKicadPaths (std::list< wxString > &paths) const
 Return a list of path environment variables local to KiCad. More...
 

Private Member Functions

bool createPathList (void)
 Build the path list using available information such as KICAD7_3DMODEL_DIR and the 3d_path_list configuration file. More...
 
bool addPath (const SEARCH_PATH &aPath)
 Check that a path is valid and adds it to the search list. More...
 
void checkEnvVarPath (const wxString &aPath)
 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. More...
 

Private Attributes

wxString m_configDir
 
std::list< SEARCH_PATHm_paths
 
int m_errflags
 
PGM_BASEm_pgm
 
PROJECTm_project
 
wxString m_curProjDir
 

Detailed Description

Provide an extensible class to resolve 3D model paths.

Initially the legacy behavior will be implemented and an incomplete path would be checked against the project directory or the KICAD7_3DMODEL_DIR environment variable. In the future a configurable set of search paths may be specified.

Definition at line 56 of file filename_resolver.h.

Constructor & Destructor Documentation

◆ FILENAME_RESOLVER()

FILENAME_RESOLVER::FILENAME_RESOLVER ( )

Definition at line 51 of file filename_resolver.cpp.

51 :
52 m_pgm( nullptr ),
53 m_project( nullptr )
54{
55 m_errflags = 0;
56}

References m_errflags.

Member Function Documentation

◆ addPath()

bool FILENAME_RESOLVER::addPath ( const SEARCH_PATH aPath)
private

Check that a path is valid and adds it to the search list.

Parameters
aPathis the alias set to be checked and added.
Returns
true if aPath is valid.

Definition at line 422 of file filename_resolver.cpp.

423{
424 if( aPath.m_Alias.empty() || aPath.m_Pathvar.empty() )
425 return false;
426
427 std::lock_guard<std::mutex> lock( mutex_resolver );
428
429 SEARCH_PATH tpath = aPath;
430
431 #ifdef _WIN32
432 while( tpath.m_Pathvar.EndsWith( wxT( "\\" ) ) )
433 tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 );
434 #else
435 while( tpath.m_Pathvar.EndsWith( wxT( "/" ) ) && tpath.m_Pathvar.length() > 1 )
436 tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 );
437 #endif
438
439 wxFileName path( ExpandEnvVarSubstitutions( tpath.m_Pathvar, m_project ), "" );
440
441 path.Normalize( FN_NORMALIZE_FLAGS );
442
443 if( !path.DirExists() )
444 {
445 if( aPath.m_Pathvar == wxS( "${KICAD7_3DMODEL_DIR}" )
446 || aPath.m_Pathvar == wxS( "${KIPRJMOD}" ) || aPath.m_Pathvar == wxS( "$(KIPRJMOD)" )
447 || aPath.m_Pathvar == wxS( "${KISYS3DMOD}" ) || aPath.m_Pathvar == wxS( "$(KISYS3DMOD)" ) )
448 {
449 // suppress the message if the missing pathvar is a system variable
450 }
451 else
452 {
453 wxString msg = _( "The given path does not exist" );
454 msg.append( wxT( "\n" ) );
455 msg.append( tpath.m_Pathvar );
456 DisplayErrorMessage( nullptr, msg );
457 }
458
459 tpath.m_Pathexp.clear();
460 }
461 else
462 {
463 tpath.m_Pathexp = path.GetFullPath();
464
465#ifdef _WIN32
466 while( tpath.m_Pathexp.EndsWith( wxT( "\\" ) ) )
467 tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 );
468#else
469 while( tpath.m_Pathexp.EndsWith( wxT( "/" ) ) && tpath.m_Pathexp.length() > 1 )
470 tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 );
471#endif
472 }
473
474 std::list< SEARCH_PATH >::iterator sPL = m_paths.begin();
475 std::list< SEARCH_PATH >::iterator ePL = m_paths.end();
476
477 while( sPL != ePL )
478 {
479 if( tpath.m_Alias == sPL->m_Alias )
480 {
481 wxString msg = _( "Alias: " );
482 msg.append( tpath.m_Alias );
483 msg.append( wxT( "\n" ) );
484 msg.append( _( "This path:" ) + wxS( " " ) );
485 msg.append( tpath.m_Pathvar );
486 msg.append( wxT( "\n" ) );
487 msg.append( _( "Existing path:" ) + wxS( " " ) );
488 msg.append( sPL->m_Pathvar );
489 DisplayErrorMessage( nullptr, _( "Bad alias (duplicate name)" ), msg );
490 return false;
491 }
492
493 ++sPL;
494 }
495
496 m_paths.push_back( tpath );
497 return true;
498}
std::list< SEARCH_PATH > m_paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:299
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:325
#define _(s)
static std::mutex mutex_resolver
wxString m_Pathvar
wxString m_Pathexp
wxString m_Alias
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:38

References _, DisplayErrorMessage(), ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, SEARCH_PATH::m_Alias, SEARCH_PATH::m_Pathexp, m_paths, SEARCH_PATH::m_Pathvar, m_project, mutex_resolver, and path.

Referenced by UpdatePathList().

◆ checkEnvVarPath()

void FILENAME_RESOLVER::checkEnvVarPath ( const wxString &  aPath)
private

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.

Definition at line 501 of file filename_resolver.cpp.

502{
503 bool useParen = false;
504
505 if( aPath.StartsWith( wxS( "$(" ) ) )
506 useParen = true;
507 else if( !aPath.StartsWith( wxS( "${" ) ) )
508 return;
509
510 size_t pEnd;
511
512 if( useParen )
513 pEnd = aPath.find( wxS( ")" ) );
514 else
515 pEnd = aPath.find( wxS( "}" ) );
516
517 if( pEnd == wxString::npos )
518 return;
519
520 wxString envar = aPath.substr( 0, pEnd + 1 );
521
522 // check if the alias exists; if not then add it to the end of the
523 // env var section of the path list
524 auto sPL = m_paths.begin();
525 auto ePL = m_paths.end();
526
527 while( sPL != ePL )
528 {
529 if( sPL->m_Alias == envar )
530 return;
531
532 if( !sPL->m_Alias.StartsWith( wxS( "${" ) ) )
533 break;
534
535 ++sPL;
536 }
537
538 SEARCH_PATH lpath;
539 lpath.m_Alias = envar;
540 lpath.m_Pathvar = lpath.m_Alias;
541 wxFileName tmpFN( ExpandEnvVarSubstitutions( lpath.m_Alias, m_project ), "" );
542
543 wxUniChar psep = tmpFN.GetPathSeparator();
544 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
545
546 if( !tmpFN.DirExists() )
547 return;
548
549 lpath.m_Pathexp = tmpFN.GetFullPath();
550
551 if( !lpath.m_Pathexp.empty() && psep == *lpath.m_Pathexp.rbegin() )
552 lpath.m_Pathexp.erase( --lpath.m_Pathexp.end() );
553
554 if( lpath.m_Pathexp.empty() )
555 return;
556
557 m_paths.insert( sPL, lpath );
558}

References ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, SEARCH_PATH::m_Alias, SEARCH_PATH::m_Pathexp, m_paths, SEARCH_PATH::m_Pathvar, and m_project.

Referenced by ResolvePath().

◆ createPathList()

bool FILENAME_RESOLVER::createPathList ( void  )
private

Build the path list using available information such as KICAD7_3DMODEL_DIR and the 3d_path_list configuration file.

Warning
Invalid paths are silently discarded and removed from the configuration file.
Returns
true if at least one valid path was found.

Definition at line 156 of file filename_resolver.cpp.

157{
158 if( !m_paths.empty() )
159 return true;
160
161 // add an entry for the default search path; at this point
162 // we cannot set a sensible default so we use an empty string.
163 // the user may change this later with a call to SetProjectDir()
164
165 SEARCH_PATH lpath;
166 lpath.m_Alias = wxS( "${KIPRJMOD}" );
167 lpath.m_Pathvar = wxS( "${KIPRJMOD}" );
168 lpath.m_Pathexp = m_curProjDir;
169 m_paths.push_back( lpath );
170 wxFileName fndummy;
171 wxUniChar psep = fndummy.GetPathSeparator();
172 std::list< wxString > epaths;
173
174 if( GetKicadPaths( epaths ) )
175 {
176 for( const wxString& currPath : epaths )
177 {
178 wxString currPathVarFormat = currPath;
179 currPathVarFormat.Prepend( wxS( "${" ) );
180 currPathVarFormat.Append( wxS( "}" ) );
181
182 wxString pathVal = ExpandEnvVarSubstitutions( currPathVarFormat, m_project );
183
184 if( pathVal.empty() )
185 {
186 lpath.m_Pathexp.clear();
187 }
188 else
189 {
190 fndummy.Assign( pathVal, "" );
191 fndummy.Normalize( FN_NORMALIZE_FLAGS );
192 lpath.m_Pathexp = fndummy.GetFullPath();
193 }
194
195 lpath.m_Alias = currPath;
196 lpath.m_Pathvar = currPath;
197
198 if( !lpath.m_Pathexp.empty() && psep == *lpath.m_Pathexp.rbegin() )
199 lpath.m_Pathexp.erase( --lpath.m_Pathexp.end() );
200
201 // we add it first with the alias set to the non-variable format
202 m_paths.push_back( lpath );
203
204 // now add it with the "new variable format ${VAR}"
205 lpath.m_Alias = currPathVarFormat;
206 m_paths.push_back( lpath );
207 }
208 }
209
210 if( m_paths.empty() )
211 return false;
212
213#ifdef DEBUG
214 wxLogTrace( MASK_3D_RESOLVER, wxS( " * [3D model] search paths:\n" ) );
215 std::list< SEARCH_PATH >::const_iterator sPL = m_paths.begin();
216
217 while( sPL != m_paths.end() )
218 {
219 wxLogTrace( MASK_3D_RESOLVER, wxS( " + %s : '%s'\n" ), (*sPL).m_Alias.GetData(),
220 (*sPL).m_Pathexp.GetData() );
221 ++sPL;
222 }
223#endif
224
225 return true;
226}
bool GetKicadPaths(std::list< wxString > &paths) const
Return a list of path environment variables local to KiCad.
#define MASK_3D_RESOLVER

References ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, GetKicadPaths(), SEARCH_PATH::m_Alias, m_curProjDir, SEARCH_PATH::m_Pathexp, m_paths, SEARCH_PATH::m_Pathvar, m_project, and MASK_3D_RESOLVER.

Referenced by ResolvePath(), Set3DConfigDir(), SetProgramBase(), and ShortenPath().

◆ GetKicadPaths()

bool FILENAME_RESOLVER::GetKicadPaths ( std::list< wxString > &  paths) const

Return a list of path environment variables local to KiCad.

This list always includes KICAD7_3DMODEL_DIR even if it is not defined locally.

Definition at line 779 of file filename_resolver.cpp.

780{
781 paths.clear();
782
783 if( !m_pgm )
784 return false;
785
786 bool hasKisys3D = false;
787
788
789 // iterate over the list of internally defined ENV VARs
790 // and add them to the paths list
793
794 while( mS != mE )
795 {
796 // filter out URLs, template directories, and known system paths
797 if( mS->first == wxS( "KICAD_PTEMPLATES" )
798 || mS->first.Matches( wxS( "KICAD*_FOOTPRINT_DIR") ) )
799 {
800 ++mS;
801 continue;
802 }
803
804 if( wxString::npos != mS->second.GetValue().find( wxS( "://" ) ) )
805 {
806 ++mS;
807 continue;
808 }
809
810 //also add the path without the ${} to act as legacy alias support for older files
811 paths.push_back( mS->first );
812
813 if( mS->first.Matches( wxS("KICAD*_3DMODEL_DIR") ) )
814 hasKisys3D = true;
815
816 ++mS;
817 }
818
819 if( !hasKisys3D )
820 paths.emplace_back( wxS("KICAD7_3DMODEL_DIR") );
821
822 return true;
823}
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:856
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER

References PGM_BASE::GetLocalEnvVariables(), and m_pgm.

Referenced by createPathList().

◆ GetPaths()

const std::list< SEARCH_PATH > * FILENAME_RESOLVER::GetPaths ( ) const

Return a pointer to the internal path list; the items in:load.

The list can be used to set up the list of search paths available to a 3D file browser.

Returns
pointer to the internal path list.

Definition at line 652 of file filename_resolver.cpp.

653{
654 return &m_paths;
655}

References m_paths.

Referenced by DIALOG_SELECT_3DMODEL::updateDirChoiceList().

◆ GetProjectDir()

wxString FILENAME_RESOLVER::GetProjectDir ( ) const

Definition at line 137 of file filename_resolver.cpp.

138{
139 return m_curProjDir;
140}

References m_curProjDir.

◆ ResolvePath()

wxString FILENAME_RESOLVER::ResolvePath ( const wxString &  aFileName,
const wxString &  aWorkingPath 
)

Determines 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 aFileName into aResolvedName if the URI is valid.

Parameters
aFileNameThe configured file path to resolve
aWorkingPathThe current working path for relative path resolutions

Definition at line 243 of file filename_resolver.cpp.

244{
245 std::lock_guard<std::mutex> lock( mutex_resolver );
246
247 if( aFileName.empty() )
248 return wxEmptyString;
249
250 if( m_paths.empty() )
252
253 // first attempt to use the name as specified:
254 wxString tname = aFileName;
255
256 #ifdef _WIN32
257 // translate from KiCad's internal UNIX-like path to MSWin paths
258 tname.Replace( wxT( "/" ), wxT( "\\" ) );
259 #endif
260
261 // Note: variable expansion must preferably be performed via a threadsafe wrapper for the
262 // getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion
263 // then we will have a race condition since wxWidgets does not assure a threadsafe wrapper
264 // for getenv().
265 tname = ExpandEnvVarSubstitutions( tname, m_project );
266
267 wxFileName tmpFN( tname );
268
269 // this case covers full paths, leading expanded vars, and paths relative to the current
270 // working directory (which is not necessarily the current project directory)
271 if( tmpFN.FileExists() )
272 {
273 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
274 tname = tmpFN.GetFullPath();
275
276 // special case: if a path begins with ${ENV_VAR} but is not in the resolver's path list
277 // then add it.
278 if( aFileName.StartsWith( wxS( "${" ) ) || aFileName.StartsWith( wxS( "$(" ) ) )
279 checkEnvVarPath( aFileName );
280
281 return tname;
282 }
283
284 // if a path begins with ${ENV_VAR}/$(ENV_VAR) and is not resolved then the file either does
285 // not exist or the ENV_VAR is not defined
286 if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
287 {
288 if( !( m_errflags & ERRFLG_ENVPATH ) )
289 {
291 wxString errmsg = "[3D File Resolver] No such path; ensure the environment var is defined";
292 errmsg.append( "\n" );
293 errmsg.append( tname );
294 errmsg.append( "\n" );
295 wxLogTrace( tracePathsAndFiles, errmsg );
296 }
297
298 return wxEmptyString;
299 }
300
301 // at this point aFileName is:
302 // a. an aliased shortened name or
303 // b. cannot be determined
304
305 // check the path relative to the current project directory;
306 // NB: this is not necessarily the same as the current working directory, which has already
307 // been checked. This case accounts for partial paths which do not contain ${KIPRJMOD}.
308 // This check is performed before checking the path relative to ${KICAD7_3DMODEL_DIR} so that
309 // users can potentially override a model within ${KICAD7_3DMODEL_DIR}.
310 if( !m_paths.begin()->m_Pathexp.empty() && !tname.StartsWith( ":" ) )
311 {
312 tmpFN.Assign( m_paths.begin()->m_Pathexp, "" );
313 wxString fullPath = tmpFN.GetPathWithSep() + tname;
314
315 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
316
317 if( wxFileName::FileExists( fullPath ) )
318 {
319 tmpFN.Assign( fullPath );
320 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
321 tname = tmpFN.GetFullPath();
322 return tname;
323 }
324
325 }
326
327 // check path relative to search path
328 if( !aWorkingPath.IsEmpty() && !tname.StartsWith( ":" ) )
329 {
330 wxString tmp = aWorkingPath;
331 tmp.Append( tmpFN.GetPathSeparator() );
332 tmp.Append( tname );
333 tmpFN.Assign( tmp );
334
335 if( tmpFN.MakeAbsolute() && tmpFN.FileExists() )
336 {
337 tname = tmpFN.GetFullPath();
338 return tname;
339 }
340 }
341
342 // check the partial path relative to ${KICAD7_3DMODEL_DIR} (legacy behavior)
343 if( !tname.StartsWith( wxS( ":" ) ) )
344 {
345 wxFileName fpath;
346 wxString fullPath( wxS( "${KICAD7_3DMODEL_DIR}" ) );
347 fullPath.Append( fpath.GetPathSeparator() );
348 fullPath.Append( tname );
349 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
350 fpath.Assign( fullPath );
351
352 if( fpath.Normalize( FN_NORMALIZE_FLAGS ) && fpath.FileExists() )
353 {
354 tname = fpath.GetFullPath();
355 return tname;
356 }
357
358 }
359
360 // at this point the filename must contain an alias or else it is invalid
361 wxString alias; // the alias portion of the short filename
362 wxString relpath; // the path relative to the alias
363
364 if( !SplitAlias( tname, alias, relpath ) )
365 {
366 if( !( m_errflags & ERRFLG_RELPATH ) )
367 {
368 // this can happen if the file was intended to be relative to ${KICAD7_3DMODEL_DIR}
369 // but ${KICAD7_3DMODEL_DIR} is not set or is incorrect.
371 wxString errmsg = "[3D File Resolver] No such path";
372 errmsg.append( wxS( "\n" ) );
373 errmsg.append( tname );
374 errmsg.append( wxS( "\n" ) );
375 wxLogTrace( tracePathsAndFiles, errmsg );
376 }
377
378 return wxEmptyString;
379 }
380
381 for( const SEARCH_PATH& path : m_paths )
382 {
383 // ${ENV_VAR} paths have already been checked; skip them
384 if( path.m_Alias.StartsWith( wxS( "${" ) ) || path.m_Alias.StartsWith( wxS( "$(" ) ) )
385 continue;
386
387 if( path.m_Alias == alias && !path.m_Pathexp.empty() )
388 {
389 wxFileName fpath( wxFileName::DirName( path.m_Pathexp ) );
390 wxString fullPath = fpath.GetPathWithSep() + relpath;
391
392 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
393
394 if( wxFileName::FileExists( fullPath ) )
395 {
396 tname = fullPath;
397
398 wxFileName tmp( fullPath );
399
400 if( tmp.Normalize( FN_NORMALIZE_FLAGS ) )
401 tname = tmp.GetFullPath();
402
403 return tname;
404 }
405 }
406 }
407
408 if( !( m_errflags & ERRFLG_ALIAS ) )
409 {
411 wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
412 errmsg.append( "\n" );
413 errmsg.append( tname.substr( 1 ) );
414 errmsg.append( "\n" );
415 wxLogTrace( tracePathsAndFiles, errmsg );
416 }
417
418 return wxEmptyString;
419}
bool createPathList(void)
Build the path list using available information such as KICAD7_3DMODEL_DIR and the 3d_path_list confi...
void checkEnvVarPath(const wxString &aPath)
Check the ${ENV_VAR} component of a path and adds it to the resolver's path list if it is not yet in ...
bool SplitAlias(const wxString &aFileName, wxString &anAlias, wxString &aRelPath) const
Return true if the given name contains an alias and populates the string anAlias with the alias and a...
#define ERRFLG_RELPATH
#define ERRFLG_ENVPATH
#define ERRFLG_ALIAS
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.

References checkEnvVarPath(), createPathList(), ERRFLG_ALIAS, ERRFLG_ENVPATH, ERRFLG_RELPATH, ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, m_errflags, m_paths, m_project, mutex_resolver, path, SplitAlias(), and tracePathsAndFiles.

Referenced by EXPORTER_PCB_VRML::ExportVrmlFootprint(), idf_export_footprint(), S3D_CACHE::load(), and PANEL_FP_PROPERTIES_3D_MODEL::validateModelExists().

◆ Set3DConfigDir()

bool FILENAME_RESOLVER::Set3DConfigDir ( const wxString &  aConfigDir)

Set the user's configuration directory for 3D models.

Parameters
aConfigDir
Returns
true if the call succeeds (directory exists).

Definition at line 59 of file filename_resolver.cpp.

60{
61 if( aConfigDir.empty() )
62 return false;
63
64 wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), "" );
65
66 cfgdir.Normalize( FN_NORMALIZE_FLAGS );
67
68 if( !cfgdir.DirExists() )
69 return false;
70
71 m_configDir = cfgdir.GetPath();
73
74 return true;
75}

References createPathList(), ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, m_configDir, and m_project.

Referenced by S3D_CACHE::Set3DConfigDir().

◆ SetProgramBase()

void FILENAME_RESOLVER::SetProgramBase ( PGM_BASE aBase)

Set a pointer to the application's PGM_BASE instance used to extract the local env vars.

Definition at line 143 of file filename_resolver.cpp.

144{
145 m_pgm = aBase;
146
147 if( !m_pgm || m_paths.empty() )
148 return;
149
150 // recreate the path list
151 m_paths.clear();
153}

References createPathList(), m_paths, and m_pgm.

Referenced by S3D_CACHE::SetProgramBase().

◆ SetProject()

bool FILENAME_RESOLVER::SetProject ( PROJECT aProject,
bool *  flgChanged = nullptr 
)

Set the current KiCad project directory as the first entry in the model path list.

Parameters
[in]aProjDircurrent project directory
[out]flgChangedoptional, set to true if directory was changed
Return values
truesuccess
falsefailure

Definition at line 78 of file filename_resolver.cpp.

79{
80 m_project = aProject;
81
82 if( !aProject )
83 return false;
84
85 wxFileName projdir( ExpandEnvVarSubstitutions( aProject->GetProjectPath(), aProject ), "" );
86
87 projdir.Normalize( FN_NORMALIZE_FLAGS );
88
89 if( !projdir.DirExists() )
90 return false;
91
92 m_curProjDir = projdir.GetPath();
93
94 if( flgChanged )
95 *flgChanged = false;
96
97 if( m_paths.empty() )
98 {
99 SEARCH_PATH al;
100 al.m_Alias = wxS( "${KIPRJMOD}" );
101 al.m_Pathvar = wxS( "${KIPRJMOD}" );
103 m_paths.push_back( al );
104
105 if( flgChanged )
106 *flgChanged = true;
107 }
108 else
109 {
110 if( m_paths.front().m_Pathexp != m_curProjDir )
111 {
112 m_paths.front().m_Pathexp = m_curProjDir;
113
114 if( flgChanged )
115 *flgChanged = true;
116 }
117 else
118 {
119 return true;
120 }
121 }
122
123#ifdef DEBUG
124 {
125 std::ostringstream ostr;
126 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
127 ostr << " * [INFO] changed project dir to ";
128 ostr << m_paths.front().m_Pathexp.ToUTF8();
129 wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
130 }
131#endif
132
133 return true;
134}
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:126

References ExpandEnvVarSubstitutions(), FN_NORMALIZE_FLAGS, PROJECT::GetProjectPath(), SEARCH_PATH::m_Alias, m_curProjDir, SEARCH_PATH::m_Pathexp, m_paths, SEARCH_PATH::m_Pathvar, m_project, and MASK_3D_RESOLVER.

Referenced by S3D_CACHE::SetProject().

◆ ShortenPath()

wxString FILENAME_RESOLVER::ShortenPath ( const wxString &  aFullPathName)

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.

Parameters
aFullPathNameis an absolute path to shorten.
Returns
the shortened path or aFullPathName.

Definition at line 561 of file filename_resolver.cpp.

562{
563 wxString fname = aFullPathName;
564
565 if( m_paths.empty() )
567
568 std::lock_guard<std::mutex> lock( mutex_resolver );
569
570 std::list< SEARCH_PATH >::const_iterator sL = m_paths.begin();
571 size_t idx;
572
573 while( sL != m_paths.end() )
574 {
575 // undefined paths do not participate in the
576 // file name shortening procedure
577 if( sL->m_Pathexp.empty() )
578 {
579 ++sL;
580 continue;
581 }
582
583 wxFileName fpath;
584
585 // in the case of aliases, ensure that we use the most recent definition
586 if( sL->m_Alias.StartsWith( wxS( "${" ) ) || sL->m_Alias.StartsWith( wxS( "$(" ) ) )
587 {
588 wxString tpath = ExpandEnvVarSubstitutions( sL->m_Alias, m_project );
589
590 if( tpath.empty() )
591 {
592 ++sL;
593 continue;
594 }
595
596 fpath.Assign( tpath, wxT( "" ) );
597 }
598 else
599 {
600 fpath.Assign( sL->m_Pathexp, wxT( "" ) );
601 }
602
603 wxString fps = fpath.GetPathWithSep();
604 wxString tname;
605
606 idx = fname.find( fps );
607
608 if( idx == 0 )
609 {
610 fname = fname.substr( fps.size() );
611
612 #ifdef _WIN32
613 // ensure only the '/' separator is used in the internal name
614 fname.Replace( wxT( "\\" ), wxT( "/" ) );
615 #endif
616
617 if( sL->m_Alias.StartsWith( wxS( "${" ) ) || sL->m_Alias.StartsWith( wxS( "$(" ) ) )
618 {
619 // old style ENV_VAR
620 tname = sL->m_Alias;
621 tname.Append( wxS( "/" ) );
622 tname.append( fname );
623 }
624 else
625 {
626 // new style alias
627 tname = ":";
628 tname.append( sL->m_Alias );
629 tname.append( wxS( ":" ) );
630 tname.append( fname );
631 }
632
633 return tname;
634 }
635
636 ++sL;
637 }
638
639#ifdef _WIN32
640 // it is strange to convert an MSWin full path to use the
641 // UNIX separator but this is done for consistency and can
642 // be helpful even when transferring project files from
643 // MSWin to *NIX.
644 fname.Replace( wxT( "\\" ), wxT( "/" ) );
645#endif
646
647 return fname;
648}

References createPathList(), ExpandEnvVarSubstitutions(), m_paths, m_project, and mutex_resolver.

Referenced by DIALOG_SELECT_3DMODEL::TransferDataFromWindow().

◆ SplitAlias()

bool FILENAME_RESOLVER::SplitAlias ( const wxString &  aFileName,
wxString &  anAlias,
wxString &  aRelPath 
) const

Return true if the given name contains an alias and populates the string anAlias with the alias and aRelPath with the relative path.

Definition at line 658 of file filename_resolver.cpp.

660{
661 anAlias.clear();
662 aRelPath.clear();
663
664 size_t searchStart = 0;
665
666 if( aFileName.StartsWith( wxT( ":" ) ) )
667 searchStart = 1;
668
669 size_t tagpos = aFileName.find( wxT( ":" ), searchStart );
670
671 if( tagpos == wxString::npos || tagpos == searchStart )
672 return false;
673
674 if( tagpos + 1 >= aFileName.length() )
675 return false;
676
677 anAlias = aFileName.substr( searchStart, tagpos - searchStart );
678 aRelPath = aFileName.substr( tagpos + 1 );
679
680 return true;
681}

Referenced by ResolvePath().

◆ UpdatePathList()

bool FILENAME_RESOLVER::UpdatePathList ( const std::vector< SEARCH_PATH > &  aPathList)

Clear the current path list and substitutes the given path list and update the path configuration file on success.

Definition at line 229 of file filename_resolver.cpp.

230{
231 wxUniChar envMarker( '$' );
232
233 while( !m_paths.empty() && envMarker != *m_paths.back().m_Alias.rbegin() )
234 m_paths.pop_back();
235
236 for( const SEARCH_PATH& path : aPathList )
237 addPath( path );
238
239 return true;
240}
bool addPath(const SEARCH_PATH &aPath)
Check that a path is valid and adds it to the search list.

References addPath(), m_paths, and path.

◆ ValidateFileName()

bool FILENAME_RESOLVER::ValidateFileName ( const wxString &  aFileName,
bool &  hasAlias 
) const

Returns true if the given path is a valid aliased relative path.

If the path contains an alias then hasAlias is set true.

Definition at line 684 of file filename_resolver.cpp.

685{
686 // Rules:
687 // 1. The generic form of an aliased 3D relative path is:
688 // ALIAS:relative/path
689 // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
690 // 3. The relative path must be a valid relative path for the platform
691 hasAlias = false;
692
693 if( aFileName.empty() )
694 return false;
695
696 wxString filename = aFileName;
697 wxString lpath;
698 size_t aliasStart = aFileName.StartsWith( ':' ) ? 1 : 0;
699 size_t aliasEnd = aFileName.find( ':', aliasStart );
700
701 // ensure that the file separators suit the current platform
702#ifdef __WINDOWS__
703 filename.Replace( wxT( "/" ), wxT( "\\" ) );
704
705 // if we see the :\ pattern then it must be a drive designator
706 if( aliasEnd != wxString::npos )
707 {
708 size_t pos1 = filename.find( wxT( ":\\" ) );
709
710 if( pos1 != wxString::npos && ( pos1 != aliasEnd || pos1 != 1 ) )
711 return false;
712
713 // if we have a drive designator then we have no alias
714 if( pos1 != wxString::npos )
715 aliasEnd = wxString::npos;
716 }
717#else
718 filename.Replace( wxT( "\\" ), wxT( "/" ) );
719#endif
720
721 // names may not end with ':'
722 if( aliasEnd == aFileName.length() -1 )
723 return false;
724
725 if( aliasEnd != wxString::npos )
726 {
727 // ensure the alias component is not empty
728 if( aliasEnd == aliasStart )
729 return false;
730
731 lpath = filename.substr( aliasStart, aliasEnd );
732
733 // check the alias for restricted characters
734 if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
735 return false;
736
737 hasAlias = true;
738 lpath = aFileName.substr( aliasEnd + 1 );
739 }
740 else
741 {
742 lpath = aFileName;
743
744 // in the case of ${ENV_VAR}|$(ENV_VAR)/path, strip the
745 // environment string before testing
746 aliasEnd = wxString::npos;
747
748 if( aFileName.StartsWith( wxS( "${" ) ) )
749 aliasEnd = aFileName.find( '}' );
750 else if( aFileName.StartsWith( wxS( "$(" ) ) )
751 aliasEnd = aFileName.find( ')' );
752
753 if( aliasEnd != wxString::npos )
754 lpath = aFileName.substr( aliasEnd + 1 );
755
756 }
757
758 // Test for forbidden chars in filenames. Should be wxFileName::GetForbiddenChars()
759 // On MSW, the list returned by wxFileName::GetForbiddenChars() contains separators
760 // '\'and '/' used here because lpath can be a full path.
761 // So remove separators
762 wxString lpath_no_sep = lpath;
763#ifdef __WINDOWS__
764 lpath_no_sep.Replace( "/", " " );
765 lpath_no_sep.Replace( "\\", " " );
766
767 // A disk identifier is allowed, and therefore remove its separator
768 if( lpath_no_sep.Length() > 1 && lpath_no_sep[1] == ':' )
769 lpath_no_sep[1] = ' ';
770#endif
771
772 if( wxString::npos != lpath_no_sep.find_first_of( wxFileName::GetForbiddenChars() ) )
773 return false;
774
775 return true;
776}

Referenced by PANEL_FP_PROPERTIES_3D_MODEL::validateModelExists().

Member Data Documentation

◆ m_configDir

wxString FILENAME_RESOLVER::m_configDir
private

Definition at line 168 of file filename_resolver.h.

Referenced by Set3DConfigDir().

◆ m_curProjDir

wxString FILENAME_RESOLVER::m_curProjDir
private

Definition at line 173 of file filename_resolver.h.

Referenced by createPathList(), GetProjectDir(), and SetProject().

◆ m_errflags

int FILENAME_RESOLVER::m_errflags
private

Definition at line 170 of file filename_resolver.h.

Referenced by FILENAME_RESOLVER(), and ResolvePath().

◆ m_paths

std::list<SEARCH_PATH> FILENAME_RESOLVER::m_paths
private

◆ m_pgm

PGM_BASE* FILENAME_RESOLVER::m_pgm
private

Definition at line 171 of file filename_resolver.h.

Referenced by GetKicadPaths(), and SetProgramBase().

◆ m_project

PROJECT* FILENAME_RESOLVER::m_project
private

The documentation for this class was generated from the following files: