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 53 of file 3d_filename_resolver.cpp.

References m_errflags, and m_pgm.

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

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 441 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().

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

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

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

References PGM_BASE::GetLocalEnvVariables(), and m_pgm.

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

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

References m_Paths.

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

855 {
856  return &m_Paths;
857 }
std::list< S3D_ALIAS > m_Paths
wxString S3D_FILENAME_RESOLVER::GetProjectDir ( void  )

Definition at line 148 of file 3d_filename_resolver.cpp.

References m_curProjDir.

149 {
150  return m_curProjDir;
151 }
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 523 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().

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

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

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

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

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

61 {
62  if( aConfigDir.empty() )
63  return false;
64 
65  wxFileName cfgdir;
66 
67  if( aConfigDir.StartsWith( "${" ) || aConfigDir.StartsWith( "$(" ) )
68  cfgdir.Assign( ExpandEnvVarSubstitutions( aConfigDir ), "" );
69  else
70  cfgdir.Assign( aConfigDir, "" );
71 
72  cfgdir.Normalize();
73 
74  if( false == cfgdir.DirExists() )
75  return false;
76 
77  m_ConfigDir = cfgdir.GetPath();
79 
80  return true;
81 }
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace 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 154 of file 3d_filename_resolver.cpp.

References createPathList(), m_Paths, and m_pgm.

155 {
156  m_pgm = aBase;
157 
158  if( NULL == m_pgm || m_Paths.empty() )
159  return;
160 
161  // recreate the path list
162  m_Paths.clear();
163  createPathList();
164 
165  return;
166 }
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 84 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.

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

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

Referenced by DLG_SELECT_3DMODEL::TransferDataFromWindow().

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

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

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

Referenced by DLG_3D_PATH_CONFIG::TransferDataFromWindow().

240 {
241  wxUniChar envMarker( '$' );
242 
243  while( !m_Paths.empty() && envMarker != *m_Paths.back().m_alias.rbegin() )
244  m_Paths.pop_back();
245 
246  size_t nI = aPathList.size();
247 
248  for( size_t i = 0; i < nI; ++i )
249  addPath( aPathList[i] );
250 
251  return writePathList();
252 }
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 979 of file 3d_filename_resolver.cpp.

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

980 {
981  // Rules:
982  // 1. The generic form of an aliased 3D relative path is:
983  // ALIAS:relative/path
984  // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
985  // 3. The relative path must be a valid relative path for the platform
986  hasAlias = false;
987 
988  if( aFileName.empty() )
989  return false;
990 
991  wxString filename = aFileName;
992  size_t pos0 = aFileName.find( ':' );
993 
994  // ensure that the file separators suit the current platform
995  #ifdef __WINDOWS__
996  filename.Replace( wxT( "/" ), wxT( "\\" ) );
997 
998  // if we see the :\ pattern then it must be a drive designator
999  if( pos0 != wxString::npos )
1000  {
1001  size_t pos1 = filename.find( wxT( ":\\" ) );
1002 
1003  if( pos1 != wxString::npos && ( pos1 != pos0 || pos1 != 1 ) )
1004  return false;
1005 
1006  // if we have a drive designator then we have no alias
1007  if( pos1 != wxString::npos )
1008  pos0 = wxString::npos;
1009  }
1010  #else
1011  filename.Replace( wxT( "\\" ), wxT( "/" ) );
1012  #endif
1013 
1014  // names may not end with ':'
1015  if( pos0 == aFileName.length() -1 )
1016  return false;
1017 
1018  if( pos0 != wxString::npos )
1019  {
1020  // ensure the alias component is not empty
1021  if( pos0 == 0 )
1022  return false;
1023 
1024  wxString lpath = filename.substr( 0, pos0 );
1025 
1026  // check the alias for restricted characters
1027  if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
1028  return false;
1029 
1030  hasAlias = true;
1031  }
1032 
1033  return true;
1034 }
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 629 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().

630 {
631  if( m_ConfigDir.empty() )
632  {
633  std::ostringstream ostr;
634  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
635  wxString errmsg = _( "3D configuration directory is unknown" );
636  ostr << " * " << errmsg.ToUTF8();
637  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
638  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
639 
640  return false;
641  }
642 
643  // skip all ${ENV_VAR} alias names
644  std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
645  std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
646 
647  while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" ) || sPL->m_alias.StartsWith( "$(" ) ) )
648  ++sPL;
649 
650  wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG );
651  wxString cfgname = cfgpath.GetFullPath();
652  std::ofstream cfgFile;
653 
654  cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
655 
656  if( !cfgFile.is_open() )
657  {
658  std::ostringstream ostr;
659  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
660  wxString errmsg = _( "Could not open configuration file" );
661  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
662  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
663  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
664 
665  return false;
666  }
667 
668  cfgFile << "#V" << CFGFILE_VERSION << "\n";
669  std::string tstr;
670 
671  while( sPL != ePL )
672  {
673  tstr = sPL->m_alias.ToUTF8();
674  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
675  tstr = sPL->m_pathvar.ToUTF8();
676  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
677  tstr = sPL->m_description.ToUTF8();
678  cfgFile << "\"" << tstr.size() << ":" << tstr << "\"\n";
679  ++sPL;
680  }
681 
682  bool bad = cfgFile.bad();
683  cfgFile.close();
684 
685  if( bad )
686  {
687  wxMessageBox( _( "Problems writing configuration file" ),
688  _( "Write 3D search path list" ) );
689 
690  return false;
691  }
692 
693  return true;
694 }
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: