KiCad PCB EDA Suite
S3D_FILENAME_RESOLVER Class Reference

#include <3d_filename_resolver.h>

Public Member Functions

 S3D_FILENAME_RESOLVER ()
 
bool Set3DConfigDir (const wxString &aConfigDir)
 Function Set3DConfigDir sets the user's configuration directory for 3D models. More...
 
bool SetProjectDir (const wxString &aProjDir, bool *flgChanged=NULL)
 Function SetProjectDir sets the current KiCad project directory as the first entry in the model path list. More...
 
wxString GetProjectDir (void)
 
void SetProgramBase (PGM_BASE *aBase)
 Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to extract the local env vars. More...
 
bool UpdatePathList (std::vector< S3D_ALIAS > &aPathList)
 Function UpdatePathList clears the current path list and substitutes the given path list, updating the path configuration file on success. More...
 
wxString ResolvePath (const wxString &aFileName)
 Function ResolvePath determines the full path of the given file name. More...
 
wxString ShortenPath (const wxString &aFullPathName)
 Function ShortenPath produces 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< S3D_ALIAS > * GetPaths (void)
 Function GetPaths returns a pointer to the internal path list; the items in:load. More...
 
bool SplitAlias (const wxString &aFileName, wxString &anAlias, wxString &aRelPath)
 Function SplitAlias returns 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)
 Function ValidateName returns true if the given path is a valid aliased relative path. More...
 
bool GetKicadPaths (std::list< wxString > &paths)
 Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always includes KISYS3DMOD even if it is not defined locally. More...
 

Private Member Functions

bool createPathList (void)
 Function createPathList builds the path list using available information such as KISYS3DMOD and the 3d_path_list configuration file. More...
 
bool addPath (const S3D_ALIAS &aPath)
 Function addPath checks that a path is valid and adds it to the search list. More...
 
bool readPathList (void)
 Function readPathList reads a list of path names from a configuration file. More...
 
bool writePathList (void)
 Function writePathList writes the current path list to a configuration file. More...
 
void checkEnvVarPath (const wxString &aPath)
 Function checkEnvVarPath checks 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< S3D_ALIASm_Paths
 
int m_errflags
 
PGM_BASEm_pgm
 
wxString m_curProjDir
 

Detailed Description

Definition at line 52 of file 3d_filename_resolver.h.

Constructor & Destructor Documentation

S3D_FILENAME_RESOLVER::S3D_FILENAME_RESOLVER ( )

Definition at line 52 of file 3d_filename_resolver.cpp.

References m_errflags, and m_pgm.

53 {
54  m_errflags = 0;
55  m_pgm = NULL;
56 }

Member Function Documentation

bool S3D_FILENAME_RESOLVER::addPath ( const S3D_ALIAS aPath)
private

Function addPath checks 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 438 of file 3d_filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), lock3D_resolver, S3D_ALIAS::m_alias, S3D_ALIAS::m_pathexp, m_Paths, and S3D_ALIAS::m_pathvar.

Referenced by readPathList(), and UpdatePathList().

439 {
440  if( aPath.m_alias.empty() || aPath.m_pathvar.empty() )
441  return false;
442 
443  wxCriticalSectionLocker lock( lock3D_resolver );
444 
445  S3D_ALIAS tpath = aPath;
446 
447  #ifdef _WIN32
448  while( tpath.m_pathvar.EndsWith( wxT( "\\" ) ) )
449  tpath.m_pathvar.erase( tpath.m_pathvar.length() - 1 );
450  #else
451  while( tpath.m_pathvar.EndsWith( wxT( "/" ) ) && tpath.m_pathvar.length() > 1 )
452  tpath.m_pathvar.erase( tpath.m_pathvar.length() - 1 );
453  #endif
454 
455  wxFileName path;
456 
457  if( tpath.m_pathvar.StartsWith( "${" ) || tpath.m_pathvar.StartsWith( "$(" ) )
458  path.Assign( ExpandEnvVarSubstitutions( tpath.m_pathvar ), "" );
459  else
460  path.Assign( tpath.m_pathvar, "" );
461 
462  path.Normalize();
463 
464  if( !path.DirExists() )
465  {
466  // suppress the message if the missing pathvar is the
467  // legacy KISYS3DMOD variable
468  if( aPath.m_pathvar.compare( wxT( "${KISYS3DMOD}" ) ) )
469  {
470  wxString msg = _( "The given path does not exist" );
471  msg.append( wxT( "\n" ) );
472  msg.append( tpath.m_pathvar );
473  wxMessageBox( msg, _( "3D model search path" ) );
474  }
475 
476  tpath.m_pathexp.clear();
477  }
478  else
479  {
480  tpath.m_pathexp = path.GetFullPath();
481 
482  #ifdef _WIN32
483  while( tpath.m_pathexp.EndsWith( wxT( "\\" ) ) )
484  tpath.m_pathexp.erase( tpath.m_pathexp.length() - 1 );
485  #else
486  while( tpath.m_pathexp.EndsWith( wxT( "/" ) ) && tpath.m_pathexp.length() > 1 )
487  tpath.m_pathexp.erase( tpath.m_pathexp.length() - 1 );
488  #endif
489  }
490 
491  wxString pname = path.GetPath();
492  std::list< S3D_ALIAS >::iterator sPL = m_Paths.begin();
493  std::list< S3D_ALIAS >::iterator ePL = m_Paths.end();
494 
495  while( sPL != ePL )
496  {
497  if( !tpath.m_alias.Cmp( sPL->m_alias ) )
498  {
499  wxString msg = _( "Alias: " );
500  msg.append( tpath.m_alias );
501  msg.append( wxT( "\n" ) );
502  msg.append( _( "This path: " ) );
503  msg.append( tpath.m_pathvar );
504  msg.append( wxT( "\n" ) );
505  msg.append( _( "Existing path: " ) );
506  msg.append( sPL->m_pathvar );
507  wxMessageBox( msg, _( "Bad alias (duplicate name)" ) );
508 
509  return false;
510  }
511 
512  ++sPL;
513  }
514 
515  m_Paths.push_back( tpath );
516  return true;
517 }
wxString m_pathvar
static wxCriticalSection lock3D_resolver
std::list< S3D_ALIAS > m_Paths
wxString m_pathexp
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
void S3D_FILENAME_RESOLVER::checkEnvVarPath ( const wxString &  aPath)
private

Function checkEnvVarPath checks 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 721 of file 3d_filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), S3D_ALIAS::m_alias, S3D_ALIAS::m_pathexp, m_Paths, and S3D_ALIAS::m_pathvar.

Referenced by ResolvePath().

722 {
723  bool useParen = false;
724 
725  if( aPath.StartsWith( "$(" ) )
726  useParen = true;
727  else if( !aPath.StartsWith( "${" ) )
728  return;
729 
730  size_t pEnd;
731 
732  if( useParen )
733  pEnd = aPath.find( ")" );
734  else
735  pEnd = aPath.find( "}" );
736 
737  if( pEnd == wxString::npos )
738  return;
739 
740  wxString envar = aPath.substr( 0, pEnd + 1 );
741 
742  // check if the alias exists; if not then add it to the end of the
743  // env var section of the path list
744  auto sPL = m_Paths.begin();
745  auto ePL = m_Paths.end();
746 
747  while( sPL != ePL )
748  {
749  if( sPL->m_alias == envar )
750  return;
751 
752  if( !sPL->m_alias.StartsWith( "${" ) )
753  break;
754 
755  ++sPL;
756  }
757 
758  S3D_ALIAS lpath;
759  lpath.m_alias = envar;
760  lpath.m_pathvar = lpath.m_alias;
761  wxFileName tmpFN;
762 
763  if( lpath.m_alias.StartsWith( "${" ) || lpath.m_alias.StartsWith( "$(" ) )
764  tmpFN.Assign( ExpandEnvVarSubstitutions( lpath.m_alias ), "" );
765  else
766  tmpFN.Assign( lpath.m_alias, "" );
767 
768  wxUniChar psep = tmpFN.GetPathSeparator();
769  tmpFN.Normalize();
770 
771  if( !tmpFN.DirExists() )
772  return;
773 
774  lpath.m_pathexp = tmpFN.GetFullPath();
775 
776  if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
777  lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
778 
779  if( lpath.m_pathexp.empty() )
780  return;
781 
782  m_Paths.insert( sPL, lpath );
783  return;
784 }
wxString m_pathvar
std::list< S3D_ALIAS > m_Paths
wxString m_pathexp
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
bool S3D_FILENAME_RESOLVER::createPathList ( void  )
private

Function createPathList builds the path list using available information such as KISYS3DMOD and the 3d_path_list configuration file.

Invalid paths are silently discarded and removed from the configuration file.

Returns
true if at least one valid path was found

Definition at line 168 of file 3d_filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), GetKicadPaths(), S3D_ALIAS::m_alias, m_ConfigDir, m_curProjDir, S3D_ALIAS::m_pathexp, m_Paths, S3D_ALIAS::m_pathvar, MASK_3D_RESOLVER, and readPathList().

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

169 {
170  if( !m_Paths.empty() )
171  return true;
172 
173  wxString kmod;
174 
175  // add an entry for the default search path; at this point
176  // we cannot set a sensible default so we use an empty string.
177  // the user may change this later with a call to SetProjectDir()
178 
179  S3D_ALIAS lpath;
180  lpath.m_alias = "${KIPRJMOD}";
181  lpath.m_pathvar = "${KIPRJMOD}";
182  lpath.m_pathexp = m_curProjDir;
183  m_Paths.push_back( lpath );
184  wxFileName fndummy;
185  wxUniChar psep = fndummy.GetPathSeparator();
186  std::list< wxString > epaths;
187 
188  if( GetKicadPaths( epaths ) )
189  {
190  for( auto i : epaths )
191  {
192  wxString pathVal = ExpandEnvVarSubstitutions( i );
193 
194  if( pathVal.empty() )
195  {
196  lpath.m_pathexp.clear();
197  }
198  else
199  {
200  fndummy.Assign( pathVal, "" );
201  fndummy.Normalize();
202  lpath.m_pathexp = fndummy.GetFullPath();
203  }
204 
205  lpath.m_alias = i;
206  lpath.m_pathvar = i;
207 
208  if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
209  lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
210 
211  m_Paths.push_back( lpath );
212  }
213  }
214 
215  if( !m_ConfigDir.empty() )
216  readPathList();
217 
218  if( m_Paths.empty() )
219  return false;
220 
221 #ifdef DEBUG
222  wxLogTrace( MASK_3D_RESOLVER, " * [3D model] search paths:\n" );
223  std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
224  std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
225 
226  while( sPL != ePL )
227  {
228  wxLogTrace( MASK_3D_RESOLVER, " + %s : '%s'\n", (*sPL).m_alias.GetData(),
229  (*sPL).m_pathexp.GetData() );
230  ++sPL;
231  }
232 #endif
233 
234  return true;
235 }
wxString m_pathvar
bool readPathList(void)
Function readPathList reads a list of path names from a configuration file.
std::list< S3D_ALIAS > m_Paths
wxString m_pathexp
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
bool GetKicadPaths(std::list< wxString > &paths)
Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always ...
#define MASK_3D_RESOLVER
bool S3D_FILENAME_RESOLVER::GetKicadPaths ( std::list< wxString > &  paths)

Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always includes KISYS3DMOD even if it is not defined locally.

Definition at line 1061 of file 3d_filename_resolver.cpp.

References PGM_BASE::GetLocalEnvVariables(), and m_pgm.

Referenced by createPathList(), and DLG_3D_PATH_CONFIG::updateEnvVars().

1062 {
1063  paths.clear();
1064 
1065  if( !m_pgm )
1066  return false;
1067 
1068  bool hasKisys3D = false;
1069 
1070 
1071  // iterate over the list of internally defined ENV VARs
1072  // and add them to the paths list
1075 
1076  while( mS != mE )
1077  {
1078  // filter out URLs, template directories, and known system paths
1079  if( mS->first == wxString( "KICAD_PTEMPLATES" )
1080  || mS->first == wxString( "KIGITHUB" )
1081  || mS->first == wxString( "KISYSMOD" ) )
1082  {
1083  ++mS;
1084  continue;
1085  }
1086 
1087  if( wxString::npos != mS->second.GetValue().find( wxString( "://" ) ) )
1088  {
1089  ++mS;
1090  continue;
1091  }
1092 
1093  wxString tmp( "${" );
1094  tmp.Append( mS->first );
1095  tmp.Append( "}" );
1096  paths.push_back( tmp );
1097 
1098  if( tmp == "${KISYS3DMOD}" )
1099  hasKisys3D = true;
1100 
1101  ++mS;
1102  }
1103 
1104  if( !hasKisys3D )
1105  paths.push_back( "${KISYS3DMOD}" );
1106 
1107  return true;
1108 }
VTBL_ENTRY const ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.h:270
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
Definition: pgm_base.h:89
const std::list< S3D_ALIAS > * S3D_FILENAME_RESOLVER::GetPaths ( void  )

Function GetPaths returns 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 878 of file 3d_filename_resolver.cpp.

References m_Paths.

Referenced by DLG_3D_PATH_CONFIG::initDialog(), and DLG_SELECT_3DMODEL::updateDirChoiceList().

879 {
880  return &m_Paths;
881 }
std::list< S3D_ALIAS > m_Paths
wxString S3D_FILENAME_RESOLVER::GetProjectDir ( void  )

Definition at line 147 of file 3d_filename_resolver.cpp.

References m_curProjDir.

Referenced by S3D_CACHE::GetProjectDir().

148 {
149  return m_curProjDir;
150 }
bool S3D_FILENAME_RESOLVER::readPathList ( void  )
private

Function readPathList reads a list of path names from a configuration file.

Returns
true if a file was found and contained at least one valid path

Definition at line 520 of file 3d_filename_resolver.cpp.

References addPath(), CFGFILE_VERSION, getHollerith(), S3D_ALIAS::m_alias, m_ConfigDir, S3D_ALIAS::m_description, m_Paths, S3D_ALIAS::m_pathvar, MASK_3D_RESOLVER, S3D_RESOLVER_CONFIG, and writePathList().

Referenced by createPathList().

521 {
522  if( m_ConfigDir.empty() )
523  {
524  std::ostringstream ostr;
525  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
526  wxString errmsg = "3D configuration directory is unknown";
527  ostr << " * " << errmsg.ToUTF8();
528  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
529  return false;
530  }
531 
532  wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG );
533  cfgpath.Normalize();
534  wxString cfgname = cfgpath.GetFullPath();
535 
536  size_t nitems = m_Paths.size();
537 
538  std::ifstream cfgFile;
539  std::string cfgLine;
540 
541  if( !wxFileName::Exists( cfgname ) )
542  {
543  std::ostringstream ostr;
544  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
545  wxString errmsg = "no 3D configuration file";
546  ostr << " * " << errmsg.ToUTF8() << " '";
547  ostr << cfgname.ToUTF8() << "'";
548  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
549  return false;
550  }
551 
552  cfgFile.open( cfgname.ToUTF8() );
553 
554  if( !cfgFile.is_open() )
555  {
556  std::ostringstream ostr;
557  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
558  wxString errmsg = "Could not open configuration file";
559  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
560  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
561  return false;
562  }
563 
564  int lineno = 0;
565  S3D_ALIAS al;
566  size_t idx;
567  int vnum = 0; // version number
568 
569  while( cfgFile.good() )
570  {
571  cfgLine.clear();
572  std::getline( cfgFile, cfgLine );
573  ++lineno;
574 
575  if( cfgLine.empty() )
576  {
577  if( cfgFile.eof() )
578  break;
579 
580  continue;
581  }
582 
583  if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 )
584  {
585  // extract the version number and parse accordingly
586  if( cfgLine.size() > 2 )
587  {
588  std::istringstream istr;
589  istr.str( cfgLine.substr( 2 ) );
590  istr >> vnum;
591  }
592 
593  continue;
594  }
595 
596  idx = 0;
597 
598  if( !getHollerith( cfgLine, idx, al.m_alias ) )
599  continue;
600 
601  // never add on KISYS3DMOD from a config file
602  if( !al.m_alias.Cmp( wxT( "KISYS3DMOD" ) ) )
603  continue;
604 
605  if( !getHollerith( cfgLine, idx, al.m_pathvar ) )
606  continue;
607 
608  if( !getHollerith( cfgLine, idx, al.m_description ) )
609  continue;
610 
611  addPath( al );
612  }
613 
614  cfgFile.close();
615 
616  if( vnum < CFGFILE_VERSION )
617  writePathList();
618 
619  if( m_Paths.size() != nitems )
620  return true;
621 
622  return false;
623 }
wxString m_pathvar
static bool getHollerith(const std::string &aString, size_t &aIndex, wxString &aResult)
std::list< S3D_ALIAS > m_Paths
#define S3D_RESOLVER_CONFIG
wxString m_description
bool addPath(const S3D_ALIAS &aPath)
Function addPath checks that a path is valid and adds it to the search list.
bool writePathList(void)
Function writePathList writes the current path list to a configuration file.
#define CFGFILE_VERSION
#define MASK_3D_RESOLVER
wxString S3D_FILENAME_RESOLVER::ResolvePath ( const wxString &  aFileName)

Function ResolvePath 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.

Definition at line 254 of file 3d_filename_resolver.cpp.

References checkEnvVarPath(), createPathList(), ERRFLG_ALIAS, ERRFLG_ENVPATH, ERRFLG_RELPATH, ExpandEnvVarSubstitutions(), lock3D_resolver, m_errflags, m_Paths, MASK_3D_RESOLVER, and SplitAlias().

Referenced by export_vrml_module(), S3D_CACHE::GetModelHash(), idf_export_module(), S3D_CACHE::load(), and PANEL_PREV_3D::UpdateModelName().

255 {
256  wxCriticalSectionLocker lock( lock3D_resolver );
257 
258  if( aFileName.empty() )
259  return wxEmptyString;
260 
261  if( m_Paths.empty() )
262  createPathList();
263 
264  // first attempt to use the name as specified:
265  wxString tname = aFileName;
266 
267  #ifdef _WIN32
268  // translate from KiCad's internal UNIX-like path to MSWin paths
269  tname.Replace( wxT( "/" ), wxT( "\\" ) );
270  #endif
271 
272  // Note: variable expansion must be performed using a threadsafe
273  // wrapper for the getenv() system call. If we allow the
274  // wxFileName::Normalize() routine to perform expansion then
275  // we will have a race condition since wxWidgets does not assure
276  // a threadsafe wrapper for getenv().
277  if( tname.StartsWith( "${" ) || tname.StartsWith( "$(" ) )
278  tname = ExpandEnvVarSubstitutions( tname );
279 
280  wxFileName tmpFN( tname );
281 
282  // in the case of absolute filenames we don't store a map item
283  if( !aFileName.StartsWith( "${" ) && !aFileName.StartsWith( "$(" )
284  && !aFileName.StartsWith( ":" ) && tmpFN.IsAbsolute() )
285  {
286  tmpFN.Normalize();
287 
288  if( tmpFN.FileExists() )
289  return tmpFN.GetFullPath();
290 
291  return wxEmptyString;
292  }
293 
294  // this case covers full paths, leading expanded vars, and paths
295  // relative to the current working directory (which is not necessarily
296  // the current project directory)
297  if( tmpFN.FileExists() )
298  {
299  tmpFN.Normalize();
300  tname = tmpFN.GetFullPath();
301 
302  // special case: if a path begins with ${ENV_VAR} but is not in the
303  // resolver's path list then add it.
304  if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
305  checkEnvVarPath( aFileName );
306 
307  return tname;
308  }
309 
310  // if a path begins with ${ENV_VAR}/$(ENV_VAR) and is not resolved then the
311  // file either does not exist or the ENV_VAR is not defined
312  if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
313  {
314  if( !( m_errflags & ERRFLG_ENVPATH ) )
315  {
317  wxString errmsg = "[3D File Resolver] No such path; ensure the environment var is defined";
318  errmsg.append( "\n" );
319  errmsg.append( tname );
320  wxLogMessage( errmsg );
321  }
322 
323  return wxEmptyString;
324  }
325 
326  // at this point aFileName is:
327  // a. an aliased shortened name or
328  // b. cannot be determined
329 
330  std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
331  std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
332 
333  // check the path relative to the current project directory;
334  // note: this is not necessarily the same as the current working
335  // directory, which has already been checked. This case accounts
336  // for partial paths which do not contain ${KIPRJMOD}.
337  // This check is performed before checking the path relative to
338  // ${KISYS3DMOD} so that users can potentially override a model
339  // within ${KISYS3DMOD}
340  if( !sPL->m_pathexp.empty() && !tname.StartsWith( ":" ) )
341  {
342  tmpFN.Assign( sPL->m_pathexp, "" );
343  wxString fullPath = tmpFN.GetPathWithSep() + tname;
344 
345  if( fullPath.StartsWith( "${" ) || fullPath.StartsWith( "$(" ) )
346  fullPath = ExpandEnvVarSubstitutions( fullPath );
347 
348  if( wxFileName::FileExists( fullPath ) )
349  {
350  tmpFN.Assign( fullPath );
351  tmpFN.Normalize();
352  tname = tmpFN.GetFullPath();
353  return tname;
354  }
355 
356  }
357 
358  // check the partial path relative to ${KISYS3DMOD} (legacy behavior)
359  if( !tname.StartsWith( ":" ) )
360  {
361  wxFileName fpath;
362  wxString fullPath( "${KISYS3DMOD}" );
363  fullPath.Append( fpath.GetPathSeparator() );
364  fullPath.Append( tname );
365  fullPath = ExpandEnvVarSubstitutions( fullPath );
366  fpath.Assign( fullPath );
367 
368  if( fpath.Normalize() && fpath.FileExists() )
369  {
370  tname = fpath.GetFullPath();
371  return tname;
372  }
373 
374  }
375 
376  // ${ENV_VAR} paths have already been checked; skip them
377  while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" )
378  || sPL->m_alias.StartsWith( "$(" ) ) )
379  ++sPL;
380 
381  // at this point the filename must contain an alias or else it is invalid
382  wxString alias; // the alias portion of the short filename
383  wxString relpath; // the path relative to the alias
384 
385  if( !SplitAlias( tname, alias, relpath ) )
386  {
387  if( !( m_errflags & ERRFLG_RELPATH ) )
388  {
389  // this can happen if the file was intended to be relative to
390  // ${KISYS3DMOD} but ${KISYS3DMOD} not set or incorrect.
392  wxString errmsg = "[3D File Resolver] No such path";
393  errmsg.append( "\n" );
394  errmsg.append( tname );
395  wxLogTrace( MASK_3D_RESOLVER, errmsg );
396  }
397 
398  return wxEmptyString;
399  }
400 
401  while( sPL != ePL )
402  {
403  if( !sPL->m_alias.Cmp( alias ) && !sPL->m_pathexp.empty() )
404  {
405  wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) );
406  wxString fullPath = fpath.GetPathWithSep() + relpath;
407 
408  if( fullPath.StartsWith( "${") || fullPath.StartsWith( "$(" ) )
409  fullPath = ExpandEnvVarSubstitutions( fullPath );
410 
411  if( wxFileName::FileExists( fullPath ) )
412  {
413  wxFileName tmp( fullPath );
414 
415  if( tmp.Normalize() )
416  tname = tmp.GetFullPath();
417 
418  return tname;
419  }
420  }
421 
422  ++sPL;
423  }
424 
425  if( !( m_errflags & ERRFLG_ALIAS ) )
426  {
428  wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
429  errmsg.append( "\n" );
430  errmsg.append( tname.substr( 1 ) );
431  wxLogTrace( MASK_3D_RESOLVER, errmsg );
432  }
433 
434  return wxEmptyString;
435 }
#define ERRFLG_ALIAS
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
#define ERRFLG_RELPATH
static wxCriticalSection lock3D_resolver
std::list< S3D_ALIAS > m_Paths
bool SplitAlias(const wxString &aFileName, wxString &anAlias, wxString &aRelPath)
Function SplitAlias returns true if the given name contains an alias and populates the string anAlias...
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
void checkEnvVarPath(const wxString &aPath)
Function checkEnvVarPath checks the ${ENV_VAR} component of a path and adds it to the resolver's path...
#define ERRFLG_ENVPATH
#define MASK_3D_RESOLVER
bool S3D_FILENAME_RESOLVER::Set3DConfigDir ( const wxString &  aConfigDir)

Function Set3DConfigDir sets the user's configuration directory for 3D models.

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

Definition at line 59 of file 3d_filename_resolver.cpp.

References createPathList(), ExpandEnvVarSubstitutions(), and m_ConfigDir.

Referenced by S3D_CACHE::Set3DConfigDir().

60 {
61  if( aConfigDir.empty() )
62  return false;
63 
64  wxFileName cfgdir;
65 
66  if( aConfigDir.StartsWith( "${" ) || aConfigDir.StartsWith( "$(" ) )
67  cfgdir.Assign( ExpandEnvVarSubstitutions( aConfigDir ), "" );
68  else
69  cfgdir.Assign( aConfigDir, "" );
70 
71  cfgdir.Normalize();
72 
73  if( false == cfgdir.DirExists() )
74  return false;
75 
76  m_ConfigDir = cfgdir.GetPath();
78 
79  return true;
80 }
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
void S3D_FILENAME_RESOLVER::SetProgramBase ( PGM_BASE aBase)

Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to extract the local env vars.

Definition at line 153 of file 3d_filename_resolver.cpp.

References createPathList(), m_Paths, and m_pgm.

Referenced by S3D_CACHE::SetProgramBase().

154 {
155  m_pgm = aBase;
156 
157  if( NULL == m_pgm || m_Paths.empty() )
158  return;
159 
160  // recreate the path list
161  m_Paths.clear();
162  createPathList();
163 
164  return;
165 }
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
std::list< S3D_ALIAS > m_Paths
bool S3D_FILENAME_RESOLVER::SetProjectDir ( const wxString &  aProjDir,
bool *  flgChanged = NULL 
)

Function SetProjectDir sets 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 83 of file 3d_filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), S3D_ALIAS::m_alias, m_curProjDir, S3D_ALIAS::m_pathexp, m_Paths, S3D_ALIAS::m_pathvar, and MASK_3D_RESOLVER.

Referenced by S3D_CACHE::SetProjectDir().

84 {
85  if( aProjDir.empty() )
86  return false;
87 
88  wxFileName projdir;
89 
90  if( aProjDir.StartsWith( "${" ) || aProjDir.StartsWith( "$(" ) )
91  projdir.Assign( ExpandEnvVarSubstitutions( aProjDir ), "" );
92  else
93  projdir.Assign( aProjDir, "" );
94 
95  projdir.Normalize();
96 
97  if( false == projdir.DirExists() )
98  return false;
99 
100  m_curProjDir = projdir.GetPath();
101 
102  if( flgChanged )
103  *flgChanged = false;
104 
105  if( m_Paths.empty() )
106  {
107  S3D_ALIAS al;
108  al.m_alias = "${KIPRJMOD}";
109  al.m_pathvar = "${KIPRJMOD}";
110  al.m_pathexp = m_curProjDir;
111  m_Paths.push_back( al );
112 
113  if( flgChanged )
114  *flgChanged = true;
115 
116  }
117  else
118  {
119  if( m_Paths.front().m_pathexp.Cmp( m_curProjDir ) )
120  {
121  m_Paths.front().m_pathexp = m_curProjDir;
122 
123  if( flgChanged )
124  *flgChanged = true;
125 
126  }
127  else
128  {
129  return true;
130  }
131  }
132 
133 #ifdef DEBUG
134  do {
135  std::ostringstream ostr;
136  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
137  ostr << " * [INFO] changed project dir to ";
138  ostr << m_Paths.front().m_pathexp.ToUTF8();
139  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
140  } while( 0 );
141 #endif
142 
143  return true;
144 }
wxString m_pathvar
std::list< S3D_ALIAS > m_Paths
wxString m_pathexp
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
#define MASK_3D_RESOLVER
wxString S3D_FILENAME_RESOLVER::ShortenPath ( const wxString &  aFullPathName)

Function ShortenPath produces 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 787 of file 3d_filename_resolver.cpp.

References createPathList(), ExpandEnvVarSubstitutions(), lock3D_resolver, and m_Paths.

Referenced by DLG_SELECT_3DMODEL::TransferDataFromWindow().

788 {
789  wxString fname = aFullPathName;
790 
791  if( m_Paths.empty() )
792  createPathList();
793 
794  wxCriticalSectionLocker lock( lock3D_resolver );
795  std::list< S3D_ALIAS >::const_iterator sL = m_Paths.begin();
796  std::list< S3D_ALIAS >::const_iterator eL = m_Paths.end();
797  size_t idx;
798 
799  while( sL != eL )
800  {
801  // undefined paths do not participate in the
802  // file name shortening procedure
803  if( sL->m_pathexp.empty() )
804  {
805  ++sL;
806  continue;
807  }
808 
809  wxFileName fpath;
810 
811  // in the case of aliases, ensure that we use the most recent definition
812  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
813  {
814  wxString tpath = ExpandEnvVarSubstitutions( sL->m_alias );
815 
816  if( tpath.empty() )
817  {
818  ++sL;
819  continue;
820  }
821 
822  fpath.Assign( tpath, wxT( "" ) );
823  }
824  else
825  {
826  fpath.Assign( sL->m_pathexp, wxT( "" ) );
827  }
828 
829  wxString fps = fpath.GetPathWithSep();
830  wxString tname;
831 
832  idx = fname.find( fps );
833 
834  if( std::string::npos != idx && 0 == idx )
835  {
836  fname = fname.substr( fps.size() );
837 
838  #ifdef _WIN32
839  // ensure only the '/' separator is used in the internal name
840  fname.Replace( wxT( "\\" ), wxT( "/" ) );
841  #endif
842 
843  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
844  {
845  // old style ENV_VAR
846  tname = sL->m_alias;
847  tname.Append( "/" );
848  tname.append( fname );
849  }
850  else
851  {
852  // new style alias
853  tname = ":";
854  tname.append( sL->m_alias );
855  tname.append( ":" );
856  tname.append( fname );
857  }
858 
859  return tname;
860  }
861 
862  ++sL;
863  }
864 
865 #ifdef _WIN32
866  // it is strange to convert an MSWin full path to use the
867  // UNIX separator but this is done for consistency and can
868  // be helpful even when transferring project files from
869  // MSWin to *NIX.
870  fname.Replace( wxT( "\\" ), wxT( "/" ) );
871 #endif
872 
873  return fname;
874 }
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
static wxCriticalSection lock3D_resolver
std::list< S3D_ALIAS > m_Paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
bool S3D_FILENAME_RESOLVER::SplitAlias ( const wxString &  aFileName,
wxString &  anAlias,
wxString &  aRelPath 
)

Function SplitAlias returns 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 884 of file 3d_filename_resolver.cpp.

Referenced by DIALOG_MODULE_MODULE_EDITOR::BrowseAndAdd3DShapeFile(), DIALOG_MODULE_BOARD_EDITOR::BrowseAndAdd3DShapeFile(), DIALOG_MODULE_MODULE_EDITOR::initModeditProperties(), DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties(), and ResolvePath().

886 {
887  anAlias.clear();
888  aRelPath.clear();
889 
890  if( !aFileName.StartsWith( wxT( ":" ) ) )
891  return false;
892 
893  size_t tagpos = aFileName.find( wxT( ":" ), 1 );
894 
895  if( wxString::npos == tagpos || 1 == tagpos )
896  return false;
897 
898  if( tagpos + 1 >= aFileName.length() )
899  return false;
900 
901  anAlias = aFileName.substr( 1, tagpos - 1 );
902  aRelPath = aFileName.substr( tagpos + 1 );
903 
904  return true;
905 }
bool S3D_FILENAME_RESOLVER::UpdatePathList ( std::vector< S3D_ALIAS > &  aPathList)

Function UpdatePathList clears the current path list and substitutes the given path list, updating the path configuration file on success.

Definition at line 238 of file 3d_filename_resolver.cpp.

References addPath(), m_Paths, and writePathList().

Referenced by DLG_3D_PATH_CONFIG::TransferDataFromWindow().

239 {
240  wxUniChar envMarker( '$' );
241 
242  while( !m_Paths.empty() && envMarker != *m_Paths.back().m_alias.rbegin() )
243  m_Paths.pop_back();
244 
245  size_t nI = aPathList.size();
246 
247  for( size_t i = 0; i < nI; ++i )
248  addPath( aPathList[i] );
249 
250  return writePathList();
251 }
std::list< S3D_ALIAS > m_Paths
bool addPath(const S3D_ALIAS &aPath)
Function addPath checks that a path is valid and adds it to the search list.
bool writePathList(void)
Function writePathList writes the current path list to a configuration file.
bool S3D_FILENAME_RESOLVER::ValidateFileName ( const wxString &  aFileName,
bool &  hasAlias 
)

Function ValidateName 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 1003 of file 3d_filename_resolver.cpp.

Referenced by DIALOG_MODULE_MODULE_EDITOR::Edit3DShapeFileName(), and DIALOG_MODULE_BOARD_EDITOR::Edit3DShapeFileName().

1004 {
1005  // Rules:
1006  // 1. The generic form of an aliased 3D relative path is:
1007  // ALIAS:relative/path
1008  // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
1009  // 3. The relative path must be a valid relative path for the platform
1010  hasAlias = false;
1011 
1012  if( aFileName.empty() )
1013  return false;
1014 
1015  wxString filename = aFileName;
1016  size_t pos0 = aFileName.find( ':' );
1017 
1018  // ensure that the file separators suit the current platform
1019  #ifdef __WINDOWS__
1020  filename.Replace( wxT( "/" ), wxT( "\\" ) );
1021 
1022  // if we see the :\ pattern then it must be a drive designator
1023  if( pos0 != wxString::npos )
1024  {
1025  size_t pos1 = filename.find( wxT( ":\\" ) );
1026 
1027  if( pos1 != wxString::npos && ( pos1 != pos0 || pos1 != 1 ) )
1028  return false;
1029 
1030  // if we have a drive designator then we have no alias
1031  if( pos1 != wxString::npos )
1032  pos0 = wxString::npos;
1033  }
1034  #else
1035  filename.Replace( wxT( "\\" ), wxT( "/" ) );
1036  #endif
1037 
1038  // names may not end with ':'
1039  if( pos0 == aFileName.length() -1 )
1040  return false;
1041 
1042  if( pos0 != wxString::npos )
1043  {
1044  // ensure the alias component is not empty
1045  if( pos0 == 0 )
1046  return false;
1047 
1048  wxString lpath = filename.substr( 0, pos0 );
1049 
1050  // check the alias for restricted characters
1051  if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
1052  return false;
1053 
1054  hasAlias = true;
1055  }
1056 
1057  return true;
1058 }
bool S3D_FILENAME_RESOLVER::writePathList ( void  )
private

Function writePathList writes the current path list to a configuration file.

Returns
true if the path list was not empty and was successfully written to the configuration file

Definition at line 626 of file 3d_filename_resolver.cpp.

References CFGFILE_VERSION, m_ConfigDir, m_Paths, MASK_3D_RESOLVER, and S3D_RESOLVER_CONFIG.

Referenced by readPathList(), and UpdatePathList().

627 {
628  if( m_ConfigDir.empty() )
629  {
630  std::ostringstream ostr;
631  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
632  wxString errmsg = _( "3D configuration directory is unknown" );
633  ostr << " * " << errmsg.ToUTF8();
634  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
635  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
636 
637  return false;
638  }
639 
640  // skip all ${ENV_VAR} alias names
641  std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
642  std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
643 
644  while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" )
645  || sPL->m_alias.StartsWith( "$(" ) ) )
646  ++sPL;
647 
648  wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG );
649  wxString cfgname = cfgpath.GetFullPath();
650  std::ofstream cfgFile;
651 
652  if( sPL == ePL )
653  {
654  wxMessageDialog md( NULL,
655  _( "3D search path list is empty;\ncontinue to write empty file?" ),
656  _( "Write 3D search path list" ), wxYES_NO );
657 
658  if( md.ShowModal() == wxID_YES )
659  {
660  cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
661 
662  if( !cfgFile.is_open() )
663  {
664  wxMessageBox( _( "Could not open configuration file" ),
665  _( "Write 3D search path list" ) );
666 
667  return false;
668  }
669 
670  cfgFile << "#V" << CFGFILE_VERSION << "\n";
671  cfgFile.close();
672  return true;
673  }
674 
675  return false;
676  }
677 
678  cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
679 
680  if( !cfgFile.is_open() )
681  {
682  std::ostringstream ostr;
683  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
684  wxString errmsg = _( "Could not open configuration file" );
685  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
686  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
687  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
688 
689  return false;
690  }
691 
692  cfgFile << "#V" << CFGFILE_VERSION << "\n";
693  std::string tstr;
694 
695  while( sPL != ePL )
696  {
697  tstr = sPL->m_alias.ToUTF8();
698  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
699  tstr = sPL->m_pathvar.ToUTF8();
700  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
701  tstr = sPL->m_description.ToUTF8();
702  cfgFile << "\"" << tstr.size() << ":" << tstr << "\"\n";
703  ++sPL;
704  }
705 
706  bool bad = cfgFile.bad();
707  cfgFile.close();
708 
709  if( bad )
710  {
711  wxMessageBox( _( "Problems writing configuration file" ),
712  _( "Write 3D search path list" ) );
713 
714  return false;
715  }
716 
717  return true;
718 }
std::list< S3D_ALIAS > m_Paths
#define S3D_RESOLVER_CONFIG
#define CFGFILE_VERSION
#define MASK_3D_RESOLVER

Member Data Documentation

wxString S3D_FILENAME_RESOLVER::m_ConfigDir
private

Definition at line 55 of file 3d_filename_resolver.h.

Referenced by createPathList(), readPathList(), Set3DConfigDir(), and writePathList().

wxString S3D_FILENAME_RESOLVER::m_curProjDir
private

Definition at line 59 of file 3d_filename_resolver.h.

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

int S3D_FILENAME_RESOLVER::m_errflags
private

Definition at line 57 of file 3d_filename_resolver.h.

Referenced by ResolvePath(), and S3D_FILENAME_RESOLVER().

PGM_BASE* S3D_FILENAME_RESOLVER::m_pgm
private

Definition at line 58 of file 3d_filename_resolver.h.

Referenced by GetKicadPaths(), S3D_FILENAME_RESOLVER(), and SetProgramBase().


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