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:255
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 695 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().

696 {
697  bool useParen = false;
698 
699  if( aPath.StartsWith( "$(" ) )
700  useParen = true;
701  else if( !aPath.StartsWith( "${" ) )
702  return;
703 
704  size_t pEnd;
705 
706  if( useParen )
707  pEnd = aPath.find( ")" );
708  else
709  pEnd = aPath.find( "}" );
710 
711  if( pEnd == wxString::npos )
712  return;
713 
714  wxString envar = aPath.substr( 0, pEnd + 1 );
715 
716  // check if the alias exists; if not then add it to the end of the
717  // env var section of the path list
718  auto sPL = m_Paths.begin();
719  auto ePL = m_Paths.end();
720 
721  while( sPL != ePL )
722  {
723  if( sPL->m_alias == envar )
724  return;
725 
726  if( !sPL->m_alias.StartsWith( "${" ) )
727  break;
728 
729  ++sPL;
730  }
731 
732  S3D_ALIAS lpath;
733  lpath.m_alias = envar;
734  lpath.m_pathvar = lpath.m_alias;
735  wxFileName tmpFN;
736 
737  if( lpath.m_alias.StartsWith( "${" ) || lpath.m_alias.StartsWith( "$(" ) )
738  tmpFN.Assign( ExpandEnvVarSubstitutions( lpath.m_alias ), "" );
739  else
740  tmpFN.Assign( lpath.m_alias, "" );
741 
742  wxUniChar psep = tmpFN.GetPathSeparator();
743  tmpFN.Normalize();
744 
745  if( !tmpFN.DirExists() )
746  return;
747 
748  lpath.m_pathexp = tmpFN.GetFullPath();
749 
750  if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
751  lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
752 
753  if( lpath.m_pathexp.empty() )
754  return;
755 
756  m_Paths.insert( sPL, lpath );
757  return;
758 }
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:255
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(), i, 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( const 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:255
size_t i
Definition: json11.cpp:597
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 1035 of file 3d_filename_resolver.cpp.

References PGM_BASE::GetLocalEnvVariables(), and m_pgm.

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

1036 {
1037  paths.clear();
1038 
1039  if( !m_pgm )
1040  return false;
1041 
1042  bool hasKisys3D = false;
1043 
1044 
1045  // iterate over the list of internally defined ENV VARs
1046  // and add them to the paths list
1049 
1050  while( mS != mE )
1051  {
1052  // filter out URLs, template directories, and known system paths
1053  if( mS->first == wxString( "KICAD_PTEMPLATES" )
1054  || mS->first == wxString( "KIGITHUB" )
1055  || mS->first == wxString( "KISYSMOD" ) )
1056  {
1057  ++mS;
1058  continue;
1059  }
1060 
1061  if( wxString::npos != mS->second.GetValue().find( wxString( "://" ) ) )
1062  {
1063  ++mS;
1064  continue;
1065  }
1066 
1067  wxString tmp( "${" );
1068  tmp.Append( mS->first );
1069  tmp.Append( "}" );
1070  paths.push_back( tmp );
1071 
1072  if( tmp == "${KISYS3DMOD}" )
1073  hasKisys3D = true;
1074 
1075  ++mS;
1076  }
1077 
1078  if( !hasKisys3D )
1079  paths.push_back( "${KISYS3DMOD}" );
1080 
1081  return true;
1082 }
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 852 of file 3d_filename_resolver.cpp.

References m_Paths.

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

853 {
854  return &m_Paths;
855 }
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.

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(), idf_export_module(), 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:255
void checkEnvVarPath(const wxString &aPath)
Function checkEnvVarPath checks the ${ENV_VAR} component of a path and adds it to the resolver&#39;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.

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:255
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.

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.

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:255
#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 761 of file 3d_filename_resolver.cpp.

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

Referenced by DLG_SELECT_3DMODEL::TransferDataFromWindow().

762 {
763  wxString fname = aFullPathName;
764 
765  if( m_Paths.empty() )
766  createPathList();
767 
768  wxCriticalSectionLocker lock( lock3D_resolver );
769  std::list< S3D_ALIAS >::const_iterator sL = m_Paths.begin();
770  std::list< S3D_ALIAS >::const_iterator eL = m_Paths.end();
771  size_t idx;
772 
773  while( sL != eL )
774  {
775  // undefined paths do not participate in the
776  // file name shortening procedure
777  if( sL->m_pathexp.empty() )
778  {
779  ++sL;
780  continue;
781  }
782 
783  wxFileName fpath;
784 
785  // in the case of aliases, ensure that we use the most recent definition
786  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
787  {
788  wxString tpath = ExpandEnvVarSubstitutions( sL->m_alias );
789 
790  if( tpath.empty() )
791  {
792  ++sL;
793  continue;
794  }
795 
796  fpath.Assign( tpath, wxT( "" ) );
797  }
798  else
799  {
800  fpath.Assign( sL->m_pathexp, wxT( "" ) );
801  }
802 
803  wxString fps = fpath.GetPathWithSep();
804  wxString tname;
805 
806  idx = fname.find( fps );
807 
808  if( std::string::npos != idx && 0 == idx )
809  {
810  fname = fname.substr( fps.size() );
811 
812  #ifdef _WIN32
813  // ensure only the '/' separator is used in the internal name
814  fname.Replace( wxT( "\\" ), wxT( "/" ) );
815  #endif
816 
817  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
818  {
819  // old style ENV_VAR
820  tname = sL->m_alias;
821  tname.Append( "/" );
822  tname.append( fname );
823  }
824  else
825  {
826  // new style alias
827  tname = ":";
828  tname.append( sL->m_alias );
829  tname.append( ":" );
830  tname.append( fname );
831  }
832 
833  return tname;
834  }
835 
836  ++sL;
837  }
838 
839 #ifdef _WIN32
840  // it is strange to convert an MSWin full path to use the
841  // UNIX separator but this is done for consistency and can
842  // be helpful even when transferring project files from
843  // MSWin to *NIX.
844  fname.Replace( wxT( "\\" ), wxT( "/" ) );
845 #endif
846 
847  return fname;
848 }
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:255
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 858 of file 3d_filename_resolver.cpp.

Referenced by DIALOG_FOOTPRINT_FP_EDITOR::BrowseAndAdd3DShapeFile(), DIALOG_FOOTPRINT_BOARD_EDITOR::BrowseAndAdd3DShapeFile(), DIALOG_FOOTPRINT_FP_EDITOR::initModeditProperties(), DIALOG_FOOTPRINT_BOARD_EDITOR::InitModeditProperties(), and ResolvePath().

860 {
861  anAlias.clear();
862  aRelPath.clear();
863 
864  if( !aFileName.StartsWith( wxT( ":" ) ) )
865  return false;
866 
867  size_t tagpos = aFileName.find( wxT( ":" ), 1 );
868 
869  if( wxString::npos == tagpos || 1 == tagpos )
870  return false;
871 
872  if( tagpos + 1 >= aFileName.length() )
873  return false;
874 
875  anAlias = aFileName.substr( 1, tagpos - 1 );
876  aRelPath = aFileName.substr( tagpos + 1 );
877 
878  return true;
879 }
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(), i, 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.
size_t i
Definition: json11.cpp:597
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 977 of file 3d_filename_resolver.cpp.

Referenced by DIALOG_FOOTPRINT_FP_EDITOR::Edit3DShapeFileName(), and DIALOG_FOOTPRINT_BOARD_EDITOR::Edit3DShapeFileName().

978 {
979  // Rules:
980  // 1. The generic form of an aliased 3D relative path is:
981  // ALIAS:relative/path
982  // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
983  // 3. The relative path must be a valid relative path for the platform
984  hasAlias = false;
985 
986  if( aFileName.empty() )
987  return false;
988 
989  wxString filename = aFileName;
990  size_t pos0 = aFileName.find( ':' );
991 
992  // ensure that the file separators suit the current platform
993  #ifdef __WINDOWS__
994  filename.Replace( wxT( "/" ), wxT( "\\" ) );
995 
996  // if we see the :\ pattern then it must be a drive designator
997  if( pos0 != wxString::npos )
998  {
999  size_t pos1 = filename.find( wxT( ":\\" ) );
1000 
1001  if( pos1 != wxString::npos && ( pos1 != pos0 || pos1 != 1 ) )
1002  return false;
1003 
1004  // if we have a drive designator then we have no alias
1005  if( pos1 != wxString::npos )
1006  pos0 = wxString::npos;
1007  }
1008  #else
1009  filename.Replace( wxT( "\\" ), wxT( "/" ) );
1010  #endif
1011 
1012  // names may not end with ':'
1013  if( pos0 == aFileName.length() -1 )
1014  return false;
1015 
1016  if( pos0 != wxString::npos )
1017  {
1018  // ensure the alias component is not empty
1019  if( pos0 == 0 )
1020  return false;
1021 
1022  wxString lpath = filename.substr( 0, pos0 );
1023 
1024  // check the alias for restricted characters
1025  if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
1026  return false;
1027 
1028  hasAlias = true;
1029  }
1030 
1031  return true;
1032 }
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  cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
653 
654  if( !cfgFile.is_open() )
655  {
656  std::ostringstream ostr;
657  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
658  wxString errmsg = _( "Could not open configuration file" );
659  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
660  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
661  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
662 
663  return false;
664  }
665 
666  cfgFile << "#V" << CFGFILE_VERSION << "\n";
667  std::string tstr;
668 
669  while( sPL != ePL )
670  {
671  tstr = sPL->m_alias.ToUTF8();
672  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
673  tstr = sPL->m_pathvar.ToUTF8();
674  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
675  tstr = sPL->m_description.ToUTF8();
676  cfgFile << "\"" << tstr.size() << ":" << tstr << "\"\n";
677  ++sPL;
678  }
679 
680  bool bad = cfgFile.bad();
681  cfgFile.close();
682 
683  if( bad )
684  {
685  wxMessageBox( _( "Problems writing configuration file" ),
686  _( "Write 3D search path list" ) );
687 
688  return false;
689  }
690 
691  return true;
692 }
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: