KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_altium_designer.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 Thomas Pointhuber <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
28
29#include <set>
30
31#include <wx/string.h>
32
33#include <font/fontconfig.h>
34#include <project.h>
36#include <altium_pcb.h>
38#include <io/io_utils.h>
41#include <pcb_io/pcb_io.h>
42#include <reporter.h>
43
44#include <board.h>
45#include <footprint.h>
46
47#include <compoundfilereader.h>
48#include <utf.h>
49
50
52 const std::vector<ALTIUM_PROJECT_VARIANT>& aVariants )
53{
54 std::map<wxString, FOOTPRINT*> fpByRef;
55 std::map<KIID, std::vector<FOOTPRINT*>> fpByUid;
56
57 for( FOOTPRINT* fp : aBoard->Footprints() )
58 {
59 fpByRef[fp->GetReference()] = fp;
60
61 // The importer stores the component unique id as the last path element. Repeated
62 // channels share one id across footprints, so collect all of them to detect ambiguity.
63 const KIID_PATH& path = fp->GetPath();
64
65 if( path.size() >= 2 )
66 fpByUid[path.back()].push_back( fp );
67 }
68
69 for( const ALTIUM_PROJECT_VARIANT& pv : aVariants )
70 {
71 aBoard->AddVariant( pv.name );
72
73 if( !pv.description.empty() && pv.description != pv.name )
74 aBoard->SetVariantDescription( pv.name, pv.description );
75
76 for( const ALTIUM_VARIANT_ENTRY& entry : pv.variations )
77 {
78 FOOTPRINT* target = nullptr;
79
80 // Prefer unique-id matching, but only when it resolves to a single footprint. A
81 // shared id (repeated channels) is ambiguous, so fall back to the designator.
82 if( !entry.uniqueId.empty() )
83 {
84 auto it = fpByUid.find( AltiumUniqueIdToKiid( entry.uniqueId ) );
85
86 if( it != fpByUid.end() && it->second.size() == 1 )
87 target = it->second.front();
88 }
89
90 if( !target )
91 {
92 auto it = fpByRef.find( entry.designator );
93
94 if( it != fpByRef.end() )
95 target = it->second;
96 }
97
98 if( !target )
99 continue;
100
101 FOOTPRINT_VARIANT* fpVariant = target->AddVariant( pv.name );
102
103 if( !fpVariant )
104 continue;
105
106 if( entry.kind == 1 )
107 {
108 fpVariant->SetDNP( true );
109 fpVariant->SetExcludedFromBOM( true );
110 fpVariant->SetExcludedFromPosFiles( true );
111 }
112 else if( entry.kind == 0 )
113 {
114 for( const auto& [key, value] : entry.alternateFields )
115 {
116 if( key.CmpNoCase( wxS( "LibReference" ) ) == 0 )
117 fpVariant->SetFieldValue( wxS( "Value" ), value );
118 else if( key.CmpNoCase( wxS( "Description" ) ) == 0 )
119 fpVariant->SetFieldValue( wxS( "Description" ), value );
120 else if( key.CmpNoCase( wxS( "Footprint" ) ) == 0 )
121 fpVariant->SetFieldValue( wxS( "Footprint" ), value );
122 }
123 }
124 }
125 }
126}
127
129 const std::map<wxString, wxString>& aParameters )
130{
131 if( !aProject )
132 return;
133
134 // Names KiCad resolves contextually (board fields, title block, special strings). Importing
135 // them as project variables would shadow nothing useful and could surprise the user, so they
136 // are left to native resolution.
137 static const std::set<wxString> reserved = {
138 wxS( "LAYER" ), wxS( "FILENAME" ), wxS( "FILEPATH" ),
139 wxS( "PROJECTNAME" ), wxS( "VARIANT" ), wxS( "VARIANT_DESC" ),
140 wxS( "ISSUE_DATE" ), wxS( "CURRENT_DATE" ), wxS( "CURRENT_TIME_LOCALE" ),
141 wxS( "CURRENT_TIME_HH_MM_SS" ), wxS( "REVISION" ), wxS( "TITLE" ),
142 wxS( "COMPANY" ), wxS( "COMMENT1" ), wxS( "COMMENT2" ),
143 wxS( "COMMENT3" ), wxS( "COMMENT4" ), wxS( "COMMENT5" ),
144 wxS( "COMMENT6" ), wxS( "COMMENT7" ), wxS( "COMMENT8" ),
145 wxS( "COMMENT9" ), wxS( "VCSHASH" ), wxS( "VCSSHORTHASH" ),
146 wxS( "KICAD_VERSION" ), wxS( "PAPER" ), wxS( "SHEETNAME" ),
147 wxS( "SHEETPATH" ), wxS( "DRC_WARNING" ), wxS( "DRC_ERROR" ),
148 wxS( "ERC_WARNING" ), wxS( "ERC_ERROR" )
149 };
150
151 std::map<wxString, wxString>& textVars = aProject->GetTextVars();
152 bool added = false;
153
154 for( const auto& [name, value] : aParameters )
155 {
156 if( reserved.count( name ) )
157 continue;
158
159 // Don't clobber a variable the user (or a prior import step) already set.
160 if( textVars.count( name ) )
161 continue;
162
163 textVars[name] = value;
164 added = true;
165 }
166
167 if( added )
168 aProject->IncrementTextVarsTicker();
169}
170
171
179
180
184
185
187 const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
188{
189 std::map<wxString, PCB_LAYER_ID> retval;
190
191 // Just return a the auto-mapped layers
192 for( INPUT_LAYER_DESC layerDesc : aInputLayerDescriptionVector )
193 {
194 retval.insert( { layerDesc.Name, layerDesc.AutoMapLayer } );
195 }
196
197 return retval;
198}
199
200
201bool PCB_IO_ALTIUM_DESIGNER::checkFileHeader( const wxString& aFileName )
202{
203 // Compound File Binary Format header
205}
206
207
208bool PCB_IO_ALTIUM_DESIGNER::CanReadBoard( const wxString& aFileName ) const
209{
210 if( !PCB_IO::CanReadBoard( aFileName ) )
211 return false;
212
213 return checkFileHeader( aFileName );
214}
215
216
217bool PCB_IO_ALTIUM_DESIGNER::CanReadLibrary( const wxString& aFileName ) const
218{
219 if( !PCB_IO::CanReadLibrary( aFileName ) )
220 return false;
221
222 return checkFileHeader( aFileName );
223}
224
225
226BOARD* PCB_IO_ALTIUM_DESIGNER::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
227 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
228{
229
230 m_props = aProperties;
231
232 m_board = aAppendToMe ? aAppendToMe : new BOARD();
233
234 // Collect the font substitution warnings (RAII - automatically reset on scope exit)
236
237 // Give the filename to the board if it's new
238 if( !aAppendToMe )
239 m_board->SetFileName( aFileName );
240
241 // clang-format off
242 const std::map<ALTIUM_PCB_DIR, std::string> mapping = {
243 { ALTIUM_PCB_DIR::FILE_HEADER, "FileHeader" },
244 { ALTIUM_PCB_DIR::ARCS6, "Arcs6" },
245 { ALTIUM_PCB_DIR::BOARD6, "Board6" },
246 { ALTIUM_PCB_DIR::BOARDREGIONS, "BoardRegions" },
247 { ALTIUM_PCB_DIR::CLASSES6, "Classes6" },
248 { ALTIUM_PCB_DIR::COMPONENTS6, "Components6" },
249 { ALTIUM_PCB_DIR::COMPONENTBODIES6, "ComponentBodies6" },
250 { ALTIUM_PCB_DIR::DIMENSIONS6, "Dimensions6" },
251 { ALTIUM_PCB_DIR::EXTENDPRIMITIVEINFORMATION, "ExtendedPrimitiveInformation" },
252 { ALTIUM_PCB_DIR::FILLS6, "Fills6" },
253 { ALTIUM_PCB_DIR::MODELS, "Models" },
254 { ALTIUM_PCB_DIR::NETS6, "Nets6" },
255 { ALTIUM_PCB_DIR::PADS6, "Pads6" },
256 { ALTIUM_PCB_DIR::POLYGONS6, "Polygons6" },
257 { ALTIUM_PCB_DIR::REGIONS6, "Regions6" },
258 { ALTIUM_PCB_DIR::RULES6, "Rules6" },
259 { ALTIUM_PCB_DIR::SHAPEBASEDREGIONS6, "ShapeBasedRegions6" },
260 { ALTIUM_PCB_DIR::TEXTS6, "Texts6" },
261 { ALTIUM_PCB_DIR::TRACKS6, "Tracks6" },
262 { ALTIUM_PCB_DIR::VIAS6, "Vias6" },
263 { ALTIUM_PCB_DIR::WIDESTRINGS6, "WideStrings6" }
264 };
265 // clang-format on
266
267 ALTIUM_PCB_COMPOUND_FILE altiumPcbFile( aFileName );
268
269 try
270 {
271 // Parse File
273 pcb.Parse( altiumPcbFile, mapping );
274 }
275 catch( CFB::CFBException& exception )
276 {
277 THROW_IO_ERROR( exception.what() );
278 }
279
280 if( m_props && m_props->count( "project_file" ) )
281 {
282 const wxString& projectFile = m_props->at( "project_file" );
283
284 auto variants = ParseAltiumProjectVariants( projectFile );
285
286 if( !variants.empty() )
288
290 ParseAltiumProjectParameters( projectFile ) );
291 }
292
293 return m_board;
294}
295
296
297long long PCB_IO_ALTIUM_DESIGNER::GetLibraryTimestamp( const wxString& aLibraryPath ) const
298{
299 // File hasn't been loaded yet.
300 if( aLibraryPath.IsEmpty() )
301 return 0;
302
303 wxFileName fn( aLibraryPath );
304
305 if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
306 return fn.GetModificationTime().GetValue().GetValue();
307 else
308 return 0;
309}
310
311
312void PCB_IO_ALTIUM_DESIGNER::loadAltiumLibrary( const wxString& aLibraryPath )
313{
314 // Suppress font substitution warnings (RAII - automatically restored on scope exit)
315 FONTCONFIG_REPORTER_SCOPE fontconfigScope( nullptr );
316
317 long long timestamp = GetLibraryTimestamp( aLibraryPath );
318
319 if( m_fplibFiles.contains( aLibraryPath ) && m_fplibFiles[aLibraryPath].m_Timestamp == timestamp )
320 return; // Already loaded
321
322 try
323 {
324 ALTIUM_FILE_CACHE& libFiles = m_fplibFiles[aLibraryPath];
325
326 if( aLibraryPath.Lower().EndsWith( wxS( ".pcblib" ) ) )
327 {
328 libFiles.m_Files.emplace_back( std::make_unique<ALTIUM_PCB_COMPOUND_FILE>( aLibraryPath ) );
329 }
330 else if( aLibraryPath.Lower().EndsWith( wxS( ".intlib" ) ) )
331 {
332 std::unique_ptr<ALTIUM_PCB_COMPOUND_FILE> lib = std::make_unique<ALTIUM_PCB_COMPOUND_FILE>( aLibraryPath );
333
334 for( const auto& [pcbLibName, pcbCfe] : lib->EnumDir( L"PCBLib" ) )
335 {
336 std::unique_ptr<ALTIUM_PCB_COMPOUND_FILE> libFile = std::make_unique<ALTIUM_PCB_COMPOUND_FILE>();
337
338 if( lib->DecodeIntLibStream( *pcbCfe, libFile.get() ) )
339 libFiles.m_Files.emplace_back( std::move( libFile ) );
340 }
341 }
342
343 libFiles.m_Timestamp = timestamp;
344 }
345 catch( CFB::CFBException& exception )
346 {
347 THROW_IO_ERROR( exception.what() );
348 }
349}
350
351
352void PCB_IO_ALTIUM_DESIGNER::FootprintEnumerate( wxArrayString& aFootprintNames,
353 const wxString& aLibraryPath, bool aBestEfforts,
354 const std::map<std::string, UTF8>* aProperties )
355{
356 loadAltiumLibrary( aLibraryPath );
357
358 if( !m_fplibFiles.contains( aLibraryPath ) )
359 return; // No footprint libraries in file, ignore.
360
361 try
362 {
363 for( std::unique_ptr<ALTIUM_PCB_COMPOUND_FILE>& altiumLibFile : m_fplibFiles[aLibraryPath].m_Files )
364 {
365 // Map code-page-dependent names to unicode names
366 CASE_INSENSITIVE_MAP<wxString> patternMap = altiumLibFile->ListLibFootprints();
367
368 const std::vector<std::string> streamName = { "Library", "Data" };
369 const CFB::COMPOUND_FILE_ENTRY* libraryData = altiumLibFile->FindStream( streamName );
370
371 if( libraryData == nullptr )
372 {
373 THROW_IO_ERROR( wxString::Format( _( "File not found: '%s'." ),
374 FormatPath( streamName ) ) );
375 }
376
377 ALTIUM_BINARY_PARSER parser( *altiumLibFile, libraryData );
378
379 std::map<wxString, wxString> properties = parser.ReadProperties();
380
381 uint32_t numberOfFootprints = parser.Read<uint32_t>();
382
383 // The number of footprints might be bogus. Following it is a list of index strings to
384 // find the footprints, and this list might actually be longer than how many footprints
385 // actually are in the library.
386 // If this case was detected, truncate the list to the number of footprints.
387 // Sample in #18452 shows that by simply truncating can get the correct footprints.
388 // Fixes https://gitlab.com/kicad/code/kicad/issues/18452.
389 // After truncation we shall no longer detect if the stream is fully parsed.
390 bool footprintListNotTruncated = true;
391
392 if ( patternMap.size() < numberOfFootprints )
393 {
394 numberOfFootprints = patternMap.size();
395 footprintListNotTruncated = false;
396 }
397
398 aFootprintNames.Alloc( numberOfFootprints );
399
400 for( size_t i = 0; i < numberOfFootprints; i++ )
401 {
403
404 wxScopedCharBuffer charBuffer = parser.ReadCharBuffer();
405 wxString fpPattern( charBuffer, wxConvISO8859_1 );
406
407 auto it = patternMap.find( fpPattern );
408
409 if( it != patternMap.end() )
410 {
411 aFootprintNames.Add( it->second ); // Proper unicode name
412 }
413 else
414 {
415 THROW_IO_ERROR( wxString::Format( "Component name not found: '%s'", fpPattern ) );
416 }
417
418 parser.SkipSubrecord();
419 }
420
421 if( parser.HasParsingError() )
422 {
423 THROW_IO_ERROR( wxString::Format( "%s stream was not parsed correctly",
424 FormatPath( streamName ) ) );
425 }
426
427 if( footprintListNotTruncated && parser.GetRemainingBytes() != 0 )
428 {
429 THROW_IO_ERROR( wxString::Format( "%s stream is not fully parsed",
430 FormatPath( streamName ) ) );
431 }
432 }
433 }
434 catch( CFB::CFBException& exception )
435 {
436 THROW_IO_ERROR( exception.what() );
437 }
438}
439
440
442 const wxString& aFootprintName, bool aKeepUUID,
443 const std::map<std::string, UTF8>* aProperties )
444{
445 loadAltiumLibrary( aLibraryPath );
446
447 if( !m_fplibFiles.contains( aLibraryPath ) )
448 THROW_IO_ERROR( wxString::Format( _( "No footprints in library '%s'" ), aLibraryPath ) );
449
450 try
451 {
452 for( std::unique_ptr<ALTIUM_PCB_COMPOUND_FILE>& altiumLibFile : m_fplibFiles[aLibraryPath].m_Files )
453 {
454 altiumLibFile->CacheLibModels();
455 auto [dirName, fpCfe] = altiumLibFile->FindLibFootprintDirName( aFootprintName );
456
457 if( dirName.IsEmpty() )
458 continue;
459
460 // Parse File
461 ALTIUM_PCB pcb( m_board, nullptr, m_layer_mapping_handler, m_reporter, aLibraryPath, aFootprintName );
462 return pcb.ParseFootprint( *altiumLibFile, aFootprintName );
463 }
464 }
465 catch( CFB::CFBException& exception )
466 {
467 THROW_IO_ERROR( exception.what() );
468 }
469
470 THROW_IO_ERROR( wxString::Format( _( "Footprint '%s' not found in '%s'." ),
471 aFootprintName,
472 aLibraryPath ) );
473}
474
475
477{
478 std::vector<FOOTPRINT*> footprints;
479
480 for( FOOTPRINT* fp : m_board->Footprints() )
481 footprints.push_back( fp );
482
483 return footprints;
484}
const char * name
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
@ EXTENDPRIMITIVEINFORMATION
Definition altium_pcb.h:56
std::vector< ALTIUM_PROJECT_VARIANT > ParseAltiumProjectVariants(const wxString &aPrjPcbPath)
Parse all [ProjectVariantN] sections from an Altium .PrjPcb project file.
std::map< wxString, wxString > ParseAltiumProjectParameters(const wxString &aPrjPcbPath)
Parse all [ParameterN] sections from an Altium .PrjPcb project file.
KIID AltiumUniqueIdToKiid(const wxString &aUniqueId)
Derive a stable KIID from an Altium component unique id.
std::map< wxString, ValueType, DETAIL::CASE_INSENSITIVE_COMPARER > CASE_INSENSITIVE_MAP
wxScopedCharBuffer ReadCharBuffer()
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
FOOTPRINT * ParseFootprint(ALTIUM_PCB_COMPOUND_FILE &altiumLibFile, const wxString &aFootprintName)
void Parse(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const std::map< ALTIUM_PCB_DIR, std::string > &aFileMapping)
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
void AddVariant(const wxString &aVariantName)
Definition board.cpp:2813
const FOOTPRINTS & Footprints() const
Definition board.h:364
void SetVariantDescription(const wxString &aVariantName, const wxString &aDescription)
Definition board.cpp:2919
RAII class to set and restore the fontconfig reporter.
Definition reporter.h:336
Variant information for a footprint.
Definition footprint.h:217
void SetExcludedFromPosFiles(bool aExclude)
Definition footprint.h:237
void SetDNP(bool aDNP)
Definition footprint.h:231
void SetFieldValue(const wxString &aFieldName, const wxString &aValue)
Set a field value override for this variant.
Definition footprint.h:259
void SetExcludedFromBOM(bool aExclude)
Definition footprint.h:234
FOOTPRINT_VARIANT * AddVariant(const wxString &aVariantName)
Add a new variant with the given name.
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition io_base.h:237
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:240
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition io_base.cpp:71
virtual void RegisterCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
LAYER_MAPPING_HANDLER m_layer_mapping_handler
Callback to get layer mapping.
static LOAD_INFO_REPORTER & GetInstance()
Definition reporter.cpp:249
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
std::vector< FOOTPRINT * > GetImportedCachedLibraryFootprints() override
Return a container with the cached library footprints generated in the last call to Load.
static bool checkFileHeader(const wxString &aFileName)
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
void loadAltiumLibrary(const wxString &aLibraryPath)
static std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
Return the automapped layers.
std::map< wxString, ALTIUM_FILE_CACHE > m_fplibFiles
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
BOARD * m_board
The board BOARD being worked on, no ownership here.
Definition pcb_io.h:353
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
Definition pcb_io.cpp:42
PCB_IO(const wxString &aName)
Definition pcb_io.h:346
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition pcb_io.h:356
Container for project specific data.
Definition project.h:66
void IncrementTextVarsTicker()
Definition project.h:115
virtual std::map< wxString, wxString > & GetTextVars() const
Definition project.cpp:130
static REPORTER & GetInstance()
Definition reporter.cpp:222
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
const std::vector< uint8_t > COMPOUND_FILE_HEADER
Definition io_utils.cpp:33
bool fileHasBinaryHeader(const wxString &aFilePath, const std::vector< uint8_t > &aHeader, size_t aOffset)
Check if a file starts with a defined binary header.
Definition io_utils.cpp:61
void ApplyAltiumProjectVariantsToBoard(BOARD *aBoard, const std::vector< ALTIUM_PROJECT_VARIANT > &aVariants)
Pcbnew PLUGIN for Altium *.PcbDoc format.
void ApplyAltiumProjectParametersToProject(PROJECT *aProject, const std::map< wxString, wxString > &aParameters)
Register Altium project parameters as KiCad project text variables so that imported board text refere...
void ApplyAltiumProjectVariantsToBoard(BOARD *aBoard, const std::vector< ALTIUM_PROJECT_VARIANT > &aVariants)
Apply parsed Altium project variants to a board by setting FOOTPRINT_VARIANT data on each footprint w...
void ApplyAltiumProjectParametersToProject(PROJECT *aProject, const std::map< wxString, wxString > &aParameters)
Register Altium project parameters as KiCad project text variables so that imported board text refere...
A project-level assembly variant parsed from an Altium .PrjPcb file.
A single component variation within an Altium project variant.
int kind
wxString uniqueId
wxString designator
std::map< wxString, wxString > alternateFields
Describes an imported layer and how it could be mapped to KiCad Layers.
std::vector< std::unique_ptr< ALTIUM_PCB_COMPOUND_FILE > > m_Files
std::string path