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 KICAD6_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 KICAD6_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 == "${KICAD6_3DMODEL_DIR}"
446 || aPath.m_Pathvar == "${KIPRJMOD}" || aPath.m_Pathvar == "$(KIPRJMOD)"
447 || aPath.m_Pathvar == "${KISYS3DMOD}" || aPath.m_Pathvar == "$(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 wxMessageBox( msg, _( "3D model search path" ) );
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 wxMessageBox( msg, _( "Bad alias (duplicate name)" ) );
490
491 return false;
492 }
493
494 ++sPL;
495 }
496
497 m_paths.push_back( tpath );
498 return true;
499}
std::list< SEARCH_PATH > m_paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:267
#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 _, 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 502 of file filename_resolver.cpp.

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

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 KICAD6_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 = "${KIPRJMOD}";
167 lpath.m_Pathvar = "${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, " * [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, " + %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 KICAD6_3DMODEL_DIR even if it is not defined locally.

Definition at line 780 of file filename_resolver.cpp.

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

654{
655 return &m_paths;
656}

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( "${" ) || aFileName.StartsWith( "$(" ) )
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 ${KICAD6_3DMODEL_DIR} so that
309 // users can potentially override a model within ${KICAD6_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 ${KICAD6_3DMODEL_DIR} (legacy behavior)
343 if( !tname.StartsWith( ":" ) )
344 {
345 wxFileName fpath;
346 wxString fullPath( "${KICAD6_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 ${KICAD6_3DMODEL_DIR}
369 // but ${KICAD6_3DMODEL_DIR} is not set or is incorrect.
371 wxString errmsg = "[3D File Resolver] No such path";
372 errmsg.append( "\n" );
373 errmsg.append( tname );
374 errmsg.append( "\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( "${" ) || path.m_Alias.StartsWith( "$(" ) )
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 KICAD6_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 = "${KIPRJMOD}";
101 al.m_Pathvar = "${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 562 of file filename_resolver.cpp.

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

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 659 of file filename_resolver.cpp.

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

Referenced by PANEL_FP_PROPERTIES_3D_MODEL::OnAdd3DModel(), PANEL_FP_PROPERTIES_3D_MODEL::ReloadModelsFromFootprint(), and 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 685 of file filename_resolver.cpp.

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

Referenced by PANEL_FP_PROPERTIES_3D_MODEL::On3DModelCellChanged(), and 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: