KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_orcad.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * Based on the dsn2kicad reference implementation and on OrCAD file format
7 * documentation from the OpenOrCadParser project (MIT licensed).
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28
30
31#include <algorithm>
32#include <cctype>
33#include <map>
34#include <string>
35#include <utility>
36#include <vector>
37
38#include <wx/string.h>
39#include <wx/translation.h>
40
41#include <compoundfilereader.h>
42#include <utf.h>
43
45#include <io/io_utils.h>
46#include <ki_exception.h>
47#include <kiid.h>
48#include <progress_reporter.h>
49
50#include <lib_symbol.h>
51#include <schematic.h>
52#include <sch_screen.h>
53#include <sch_sheet.h>
54#include <sch_sheet_path.h>
55
61
62
63std::string OrcadNormalizeCfbName( const std::string& aName )
64{
65 std::string name = aName;
66 std::replace( name.begin(), name.end(), '\x03', ':' );
67 return name;
68}
69
70
71namespace
72{
73
74std::vector<char> readStream( const ALTIUM_COMPOUND_FILE& aFile,
75 const CFB::COMPOUND_FILE_ENTRY* aEntry )
76{
77 const CFB::CompoundFileReader& reader = aFile.GetCompoundFileReader();
78
79 // Stream cannot exceed file; corrupt entry claiming more must not drive huge allocation
80 uint64_t size = reader.GetStreamSize( aEntry );
81
82 if( size > reader.GetBufferLen() )
83 THROW_IO_ERROR( wxS( "OrCAD stream size exceeds the compound file" ) );
84
85 std::vector<char> data( static_cast<size_t>( size ) );
86
87 if( !data.empty() )
88 reader.ReadFile( aEntry, 0, data.data(), data.size() );
89
90 return data;
91}
92
93
94// Direct children of storage, filtered to streams (aStreams) or sub-storages, in directory order.
95std::vector<std::pair<std::string, const CFB::COMPOUND_FILE_ENTRY*>>
96enumChildren( const ALTIUM_COMPOUND_FILE& aFile, const CFB::COMPOUND_FILE_ENTRY* aParent,
97 bool aStreams )
98{
99 std::vector<std::pair<std::string, const CFB::COMPOUND_FILE_ENTRY*>> out;
100
101 const CFB::CompoundFileReader& reader = aFile.GetCompoundFileReader();
102
103 reader.EnumFiles( aParent, 1,
104 [&]( const CFB::COMPOUND_FILE_ENTRY* aEntry, const CFB::utf16string&, int ) -> int
105 {
106 if( reader.IsStream( aEntry ) == aStreams )
107 out.emplace_back( OrcadNormalizeCfbName( UTF16ToUTF8( aEntry->name ) ), aEntry );
108
109 return 0;
110 } );
111
112 return out;
113}
114
115
116std::string lowerCopy( const std::string& aText )
117{
118 std::string out = aText;
119
120 std::transform( out.begin(), out.end(), out.begin(),
121 []( unsigned char c )
122 {
123 return static_cast<char>( std::tolower( c ) );
124 } );
125
126 return out;
127}
128
129} // namespace
130
131
132bool SCH_IO_ORCAD::CanReadSchematicFile( const wxString& aFileName ) const
133{
134 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
135 return false;
136
137 // .dsn also names plain-text SPECCTRA session files; OrCAD design is OLE2/CFB compound doc
139 return false;
140
141 try
142 {
143 ALTIUM_COMPOUND_FILE cfbFile( aFileName );
144
145 const CFB::CompoundFileReader& reader = cfbFile.GetCompoundFileReader();
146 const CFB::COMPOUND_FILE_ENTRY* root = reader.GetRootEntry();
147
148 if( !root )
149 return false;
150
151 if( !cfbFile.FindStreamSingleLevel( root, "Library", true ) )
152 return false;
153
154 return cfbFile.FindStreamSingleLevel( root, "Views", false ) != nullptr
155 || cfbFile.FindStreamSingleLevel( root, "Schematics", false ) != nullptr;
156 }
157 catch( const IO_ERROR& )
158 {
159 return false;
160 }
161 catch( const CFB::CFBException& )
162 {
163 return false;
164 }
165 catch( const std::exception& )
166 {
167 return false;
168 }
169}
170
171
172SCH_SHEET* SCH_IO_ORCAD::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic,
173 SCH_SHEET* aAppendToMe,
174 const std::map<std::string, UTF8>* aProperties )
175{
176 wxASSERT( !aFileName.IsEmpty() && aSchematic );
177
178 SCH_SHEET* rootSheet = nullptr;
179
180 if( aAppendToMe )
181 {
182 wxCHECK_MSG( aSchematic->IsValid(), nullptr,
183 wxS( "Can't append to a schematic with no root!" ) );
184 rootSheet = aAppendToMe;
185 }
186 else
187 {
188 rootSheet = new SCH_SHEET( aSchematic );
189 rootSheet->SetFileName( aFileName );
190 aSchematic->SetTopLevelSheets( { rootSheet } );
191 }
192
193 if( !rootSheet->GetScreen() )
194 {
195 SCH_SCREEN* screen = new SCH_SCREEN( aSchematic );
196 screen->SetFileName( aFileName );
197 rootSheet->SetScreen( screen );
198
199 // Top-level sheet UUID must match schematic file UUID
200 const_cast<KIID&>( rootSheet->m_Uuid ) = screen->GetUuid();
201 }
202
204 {
205 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
206
207 if( !m_progressReporter->KeepRefreshing() )
208 THROW_IO_ERROR( _( "Open canceled by user." ) );
209 }
210
211 ORCAD_WARN_FN warnFn = [this]( const wxString& aMsg )
212 {
213 if( m_reporter )
214 m_reporter->Report( aMsg, RPT_SEVERITY_WARNING );
215 };
216
217 ORCAD_DESIGN design;
218
219 try
220 {
221 ALTIUM_COMPOUND_FILE cfbFile( aFileName );
222
223 const CFB::CompoundFileReader& reader = cfbFile.GetCompoundFileReader();
224 const CFB::COMPOUND_FILE_ENTRY* root = reader.GetRootEntry();
225
226 // 'Library' stream: version, fonts, string table
227 const CFB::COMPOUND_FILE_ENTRY* libraryEntry =
228 cfbFile.FindStreamSingleLevel( root, "Library", true );
229
230 if( !libraryEntry )
231 {
232 THROW_IO_ERROR( _( "The file does not contain the 'Library' stream of an OrCAD "
233 "Capture design." ) );
234 }
235
236 design.library = OrcadParseLibrary( readStream( cfbFile, libraryEntry ) );
237
238 // Pre-2003 designs use pre-preamble framing; pages via v2 reader, symbol bodies
239 // (v2 cache framing undecoded) synthesized as placeholders
240 bool isV2 = design.library.versionMajor < 3;
241
242 // 'Cache' stream: symbol defs and package pin maps
243 if( isV2 )
244 {
245 warnFn( _( "This is a pre-2003 OrCAD design; symbol graphics are synthesized as "
246 "placeholders (the legacy symbol cache format is not decoded)." ) );
247 }
248 else if( const CFB::COMPOUND_FILE_ENTRY* cacheEntry =
249 cfbFile.FindStreamSingleLevel( root, "Cache", true ) )
250 {
251 OrcadParseCache( readStream( cfbFile, cacheEntry ), design.library.strings, warnFn,
252 design.symbols, design.packages );
253 }
254 else
255 {
256 warnFn( _( "The design has no 'Cache' stream; placeholder symbols will be "
257 "synthesized for all parts." ) );
258 }
259
260 // 'Packages/<name>' streams: locally modified parts, same framing
261 if( const CFB::COMPOUND_FILE_ENTRY* packagesStorage =
262 !isV2 ? cfbFile.FindStreamSingleLevel( root, "Packages", false ) : nullptr )
263 {
264 for( const auto& [streamName, entry] : enumChildren( cfbFile, packagesStorage, true ) )
265 {
266 std::map<std::string, ORCAD_SYMBOL_DEF> extraSymbols;
267 std::map<std::string, ORCAD_PACKAGE> extraPackages;
268
269 try
270 {
271 OrcadParseCache( readStream( cfbFile, entry ), design.library.strings,
272 warnFn, extraSymbols, extraPackages );
273 }
274 catch( const IO_ERROR& e )
275 {
276 // CFB entry names UTF-16 in container, UTF-8 here
277 warnFn( wxString::Format( _( "Package stream '%s' could not be parsed: %s" ),
278 wxString::FromUTF8( streamName ), e.What() ) );
279 continue;
280 }
281
283 std::move( extraSymbols ), std::move( extraPackages ) );
284 }
285 }
286
287 // 'Views/<folder>': one storage per schematic folder
288 const CFB::COMPOUND_FILE_ENTRY* viewsStorage =
289 cfbFile.FindStreamSingleLevel( root, "Views", false );
290
291 if( !viewsStorage )
292 {
293 THROW_IO_ERROR( _( "The file does not contain a 'Views' storage; it is not a "
294 "supported OrCAD Capture design." ) );
295 }
296
297 std::vector<std::string> folders;
298 std::map<std::string, const CFB::COMPOUND_FILE_ENTRY*> folderEntries;
299
300 for( const auto& [folderName, entry] : enumChildren( cfbFile, viewsStorage, false ) )
301 {
302 if( folderEntries.emplace( folderName, entry ).second )
303 folders.push_back( folderName );
304 }
305
306 std::sort( folders.begin(), folders.end() );
307
308 if( folders.empty() )
309 THROW_IO_ERROR( _( "The design contains no schematic folders." ) );
310
311 // Root folder = folder matching Library schematic name (any case); others are
312 // hierarchical children, skipped here
313 std::string rootFolder;
314 std::string schematicName = lowerCopy( design.library.schematicName );
315
316 if( !schematicName.empty() )
317 {
318 for( const std::string& folder : folders )
319 {
320 if( lowerCopy( folder ) == schematicName )
321 {
322 rootFolder = folder;
323 break;
324 }
325 }
326 }
327
328 if( rootFolder.empty() )
329 rootFolder = folders.front();
330
331 design.name = design.library.schematicName.empty() ? rootFolder
332 : design.library.schematicName;
333
334 // Hierarchical designs split pages across sibling folders linked by block instances;
335 // import all as flat pages (root first) so nothing dropped. Hierarchy streams yield
336 // occurrence designators and block->child-folder links, merged design-wide
337 std::map<uint32_t, std::string> hierarchyLinks;
338
339 auto parseFolderPages = [&]( const std::string& aFolderName,
340 const CFB::COMPOUND_FILE_ENTRY* aFolderEntry,
341 std::vector<ORCAD_RAW_PAGE>& aOutPages )
342 {
343 const CFB::COMPOUND_FILE_ENTRY* pagesStorage =
344 cfbFile.FindStreamSingleLevel( aFolderEntry, "Pages", false );
345
346 std::vector<std::string> available;
347 std::map<std::string, const CFB::COMPOUND_FILE_ENTRY*> pageEntries;
348
349 if( pagesStorage )
350 {
351 for( const auto& [pageName, entry] : enumChildren( cfbFile, pagesStorage, true ) )
352 {
353 if( pageEntries.emplace( pageName, entry ).second )
354 available.push_back( pageName );
355 }
356 }
357
358 // Display order from folder's 'Schematic' stream; fall back to name order if absent
359 std::vector<std::string> ordered;
360 bool orderKnown = false;
361
362 if( const CFB::COMPOUND_FILE_ENTRY* orderEntry =
363 cfbFile.FindStreamSingleLevel( aFolderEntry, "Schematic", true ) )
364 {
365 try
366 {
367 for( const std::string& pageName :
368 OrcadParsePageOrder( readStream( cfbFile, orderEntry ) ) )
369 {
370 if( pageEntries.count( pageName )
371 && std::find( ordered.begin(), ordered.end(), pageName )
372 == ordered.end() )
373 {
374 ordered.push_back( pageName );
375 }
376 }
377
378 orderKnown = true;
379 }
380 catch( const IO_ERROR& e )
381 {
382 warnFn( wxString::Format(
383 _( "The page display order for schematic folder '%s' could not be "
384 "read (%s); pages are imported in name order." ),
385 wxString::FromUTF8( aFolderName ), e.What() ) );
386 ordered.clear();
387 }
388 }
389
390 if( orderKnown )
391 {
392 for( const std::string& pageName : available )
393 {
394 if( std::find( ordered.begin(), ordered.end(), pageName ) == ordered.end() )
395 ordered.push_back( pageName );
396 }
397 }
398 else
399 {
400 ordered = available;
401 std::sort( ordered.begin(), ordered.end() );
402 }
403
404 for( const std::string& pageName : ordered )
405 {
406 try
407 {
408 std::vector<char> pageData = readStream( cfbFile, pageEntries[pageName] );
409
410 aOutPages.push_back( isV2 ? OrcadParsePageV2( pageData, design.library.strings,
411 warnFn )
412 : OrcadParsePage( pageData, design.library.strings,
413 warnFn ) );
414 }
415 catch( const IO_ERROR& e )
416 {
417 warnFn( wxString::Format( _( "Page '%s' could not be parsed and was "
418 "skipped: %s" ),
419 wxString::FromUTF8( pageName ), e.What() ) );
420 }
421 }
422 };
423
424 parseFolderPages( rootFolder, folderEntries[rootFolder], design.pages );
425
426 // Root folder's Hierarchy stream holds whole occurrence tree (part refdes + nested blocks)
427 if( const CFB::COMPOUND_FILE_ENTRY* hierarchyEntry =
428 cfbFile.FindStream( folderEntries[rootFolder], { "Hierarchy", "Hierarchy" } ) )
429 {
430 std::vector<char> hierarchyData = readStream( cfbFile, hierarchyEntry );
431
432 design.occurrenceRoot = OrcadReadOccurrenceTree( hierarchyData, warnFn );
433
434 if( design.occurrenceRoot.blocks.empty() && design.occurrenceRoot.partRefs.empty() )
435 {
436 // Legacy/unreadable tree: scan-recover flat root-scope refs and block links,
437 // rebuild flat block occurrences so converter still schedules each child once
438 hierarchyLinks = OrcadReadHierarchyLinks( hierarchyData, design.library.strings,
439 warnFn, &design.occurrenceRoot.partRefs );
440
441 for( const auto& [dbId, childName] : hierarchyLinks )
442 {
443 ORCAD_OCC_BLOCK block;
444 block.targetDbId = dbId;
445 block.childFolder = childName;
446 design.occurrenceRoot.blocks.push_back( std::move( block ) );
447 }
448 }
449
450 // Block instance dbId -> child folder name, from occurrence tree
451 std::function<void( const ORCAD_OCC_SCOPE& )> collectLinks =
452 [&]( const ORCAD_OCC_SCOPE& aScope )
453 {
454 for( const ORCAD_OCC_BLOCK& block : aScope.blocks )
455 {
456 hierarchyLinks[block.targetDbId] = block.childFolder;
457 collectLinks( block.scope );
458 }
459 };
460
461 collectLinks( design.occurrenceRoot );
462 }
463
464 if( design.pages.empty() )
465 THROW_IO_ERROR( _( "No schematic pages could be read from the design." ) );
466
467 // Parse pages of every block-reachable folder once; instantiated per block occurrence
468 // during conversion. Unreferenced alternate/backup folders left out
469 std::map<std::string, std::string> folderByLowerName;
470
471 for( const std::string& folder : folders )
472 folderByLowerName.emplace( lowerCopy( folder ), folder );
473
474 for( const auto& [dbId, childName] : hierarchyLinks )
475 {
476 std::string key = lowerCopy( childName );
477
478 if( key == lowerCopy( rootFolder ) || design.childFolderPages.count( key ) )
479 continue;
480
481 auto childIt = folderByLowerName.find( key );
482
483 if( childIt != folderByLowerName.end() )
484 parseFolderPages( childIt->second, folderEntries[childIt->second],
485 design.childFolderPages[key] );
486 }
487
488 for( ORCAD_RAW_PAGE& page : design.pages )
489 {
490 if( OrcadPageHasHierarchyBlocks( page ) )
491 design.hasHierarchyBlocks = true;
492
493 for( ORCAD_DRAWN_INSTANCE& block : page.blocks )
494 {
495 if( block.childName.empty() )
496 {
497 auto it = hierarchyLinks.find( block.dbId );
498
499 if( it != hierarchyLinks.end() )
500 block.childName = it->second;
501 }
502 }
503 }
504 }
505 catch( const CFB::CFBException& e )
506 {
507 THROW_IO_ERROR( e.what() );
508 }
509
510 ORCAD_CONVERTER converter( design, aSchematic, m_reporter, m_progressReporter );
511
512 converter.Convert( rootSheet );
513
515 aSchematic->FixupJunctionsAfterImport();
516
517 return rootSheet;
518}
519
520
521const std::vector<std::unique_ptr<LIB_SYMBOL>>&
522SCH_IO_ORCAD::loadOlbSymbols( const wxString& aLibraryPath )
523{
524 if( auto it = m_libCache.find( aLibraryPath ); it != m_libCache.end() )
525 return it->second;
526
527 ORCAD_WARN_FN warnFn = [this]( const wxString& aMsg )
528 {
529 if( m_reporter )
530 m_reporter->Report( aMsg, RPT_SEVERITY_WARNING );
531 };
532
533 ORCAD_DESIGN design;
534
535 try
536 {
537 ALTIUM_COMPOUND_FILE cfbFile( aLibraryPath );
538
539 const CFB::CompoundFileReader& reader = cfbFile.GetCompoundFileReader();
540 const CFB::COMPOUND_FILE_ENTRY* root = reader.GetRootEntry();
541
542 const CFB::COMPOUND_FILE_ENTRY* libraryEntry =
543 cfbFile.FindStreamSingleLevel( root, "Library", true );
544
545 if( !libraryEntry )
546 THROW_IO_ERROR( _( "The file is not an OrCAD Capture library (no 'Library' stream)." ) );
547
548 design.library = OrcadParseLibrary( readStream( cfbFile, libraryEntry ) );
549
550 bool isV2 = design.library.versionMajor < 3;
551
552 // Parse one stream, tolerating a single bad/oversized stream without aborting the
553 // library. Modern streams use preamble-framed cache reader; v2.0 uses short-prefix readers
554 auto parseStream = [&]( const CFB::COMPOUND_FILE_ENTRY* aEntry, bool aIsPackage )
555 {
556 std::map<std::string, ORCAD_SYMBOL_DEF> extraSymbols;
557 std::map<std::string, ORCAD_PACKAGE> extraPackages;
558
559 try
560 {
561 std::vector<char> data = readStream( cfbFile, aEntry );
562
563 if( isV2 && aIsPackage )
564 OrcadParseOlbPackageStreamV2( data, design.library.strings, extraSymbols,
565 extraPackages );
566 else if( isV2 )
567 OrcadParseOlbSymbolStreamV2( data, design.library.strings, extraSymbols );
568 else
569 OrcadParseCache( data, design.library.strings, warnFn, extraSymbols,
570 extraPackages );
571 }
572 catch( const std::exception& )
573 {
574 // Single bad stream must not abort whole library
575 return;
576 }
577
578 OrcadMergeCacheStreams( design.symbols, design.packages, std::move( extraSymbols ),
579 std::move( extraPackages ) );
580 };
581
582 // Design 'Cache' usually empty in a library; read anyway for rare cached symbol
583 if( !isV2 )
584 {
585 if( const CFB::COMPOUND_FILE_ENTRY* cacheEntry =
586 cfbFile.FindStreamSingleLevel( root, "Cache", true ) )
587 {
588 parseStream( cacheEntry, false );
589 }
590 }
591
592 // Symbols and parts live one per stream under 'Symbols' and 'Packages' storages
593 for( const char* storageName : { "Symbols", "Packages" } )
594 {
595 bool isPackage = std::string( storageName ) == "Packages";
596
597 const CFB::COMPOUND_FILE_ENTRY* storage =
598 cfbFile.FindStreamSingleLevel( root, storageName, false );
599
600 if( storage )
601 {
602 for( const auto& [streamName, entry] : enumChildren( cfbFile, storage, true ) )
603 {
604 // '$Types$' and similar helper streams are not symbol defs
605 if( !streamName.empty() && streamName.front() == '$' )
606 continue;
607
608 parseStream( entry, isPackage );
609 }
610 }
611 }
612 }
613 catch( const CFB::CFBException& e )
614 {
615 THROW_IO_ERROR( e.what() );
616 }
617 catch( const IO_ERROR& )
618 {
619 // Reportable errors (e.g. pre-2003 version gate) propagate
620 throw;
621 }
622 catch( const std::exception& e )
623 {
624 // Malformed Library stream can drive over-sized allocation; degrade to recovered symbols
625 warnFn( wxString::Format( _( "The OrCAD library could not be fully parsed (%s); some "
626 "symbols may be missing." ),
627 wxString::FromUTF8( e.what() ) ) );
628 }
629
630 ORCAD_CONVERTER converter( design, nullptr, m_reporter, m_progressReporter );
631
632 // Build fully before caching so mid-parse failure does not cache an empty library
633 std::vector<std::unique_ptr<LIB_SYMBOL>> built;
634
635 for( LIB_SYMBOL* symbol : converter.BuildSymbolLibrary() )
636 built.emplace_back( symbol );
637
638 return m_libCache[aLibraryPath] = std::move( built );
639}
640
641
642void SCH_IO_ORCAD::EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath,
643 const std::map<std::string, UTF8>* )
644{
645 for( const std::unique_ptr<LIB_SYMBOL>& symbol : loadOlbSymbols( aLibraryPath ) )
646 aSymbolNameList.Add( symbol->GetName() );
647}
648
649
650void SCH_IO_ORCAD::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
651 const wxString& aLibraryPath,
652 const std::map<std::string, UTF8>* )
653{
654 for( const std::unique_ptr<LIB_SYMBOL>& symbol : loadOlbSymbols( aLibraryPath ) )
655 aSymbolList.push_back( symbol.get() );
656}
657
658
659LIB_SYMBOL* SCH_IO_ORCAD::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
660 const std::map<std::string, UTF8>* )
661{
662 for( const std::unique_ptr<LIB_SYMBOL>& symbol : loadOlbSymbols( aLibraryPath ) )
663 {
664 if( symbol->GetName() == aAliasName )
665 return symbol.get();
666 }
667
668 return nullptr;
669}
const char * name
const CFB::CompoundFileReader & GetCompoundFileReader() const
const CFB::COMPOUND_FILE_ENTRY * FindStreamSingleLevel(const CFB::COMPOUND_FILE_ENTRY *aEntry, const std::string aName, const bool aIsStream) const
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
const KIID m_Uuid
Definition eda_item.h:531
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
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Definition kiid.h:44
Define a library symbol object.
Definition lib_symbol.h:114
Builds the KiCad schematic from a parsed OrCAD design.
SCH_SHEET * Convert(SCH_SHEET *aRootSheet)
Populate the schematic.
std::vector< LIB_SYMBOL * > BuildSymbolLibrary()
Build KiCad library symbols from the design cache and packages alone (no schematic pages),...
Holds all the data relating to one schematic.
Definition schematic.h:90
int FixupJunctionsAfterImport()
Add junctions to this schematic where required.
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:174
void SetTopLevelSheets(const std::vector< SCH_SHEET * > &aSheets)
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:189
const std::vector< std::unique_ptr< LIB_SYMBOL > > & loadOlbSymbols(const wxString &aLibraryPath)
Parse an .OLB and build its KiCad library symbols, cached by library path.
std::map< wxString, std::vector< std::unique_ptr< LIB_SYMBOL > > > m_libCache
bool CanReadSchematicFile(const wxString &aFileName) const override
The .dsn extension collides with SPECCTRA PCB session files (plain text), so beyond the extension gat...
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Orchestration: root sheet/screen boilerplate (honoring aAppendToMe), CFB open, Library parse + versio...
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Enumerate the symbols of an OrCAD .OLB library (an OLE2/CFB compound document with the same Library/C...
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition sch_io.cpp:45
const KIID & GetUuid() const
Definition sch_screen.h:529
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:376
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
#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:29
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:57
void OrcadMergeCacheStreams(std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols, std::map< std::string, ORCAD_PACKAGE > &aPackages, std::map< std::string, ORCAD_SYMBOL_DEF > &&aExtraSymbols, std::map< std::string, ORCAD_PACKAGE > &&aExtraPackages)
Merge the results of a 'Packages/<name>' stream (locally modified parts) into the main cache maps: a ...
void OrcadParseCache(const std::vector< char > &aData, const std::vector< std::string > &aStrings, const ORCAD_WARN_FN &aWarn, std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols, std::map< std::string, ORCAD_PACKAGE > &aPackages)
Scan a Cache-framed stream (the 'Cache' stream itself, or any 'Packages/<name>' stream — they share t...
Parsers for the DSN 'Cache' stream and the 'Packages/<name>' streams: symbol definitions with graphic...
ORCAD_CONVERTER turns a parsed ORCAD_DESIGN into KiCad schematic objects.
ORCAD_LIBRARY_INFO OrcadParseLibrary(const std::vector< char > &aData)
Parse the whole 'Library' stream.
Parser for the DSN root 'Library' stream: format version, fonts, page settings and the global string ...
void OrcadParseOlbSymbolStreamV2(const std::vector< char > &aData, const std::vector< std::string > &aStrings, std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols)
Parse one v2.0 .OLB 'Symbols/<name>' stream (a single special symbol: power, port,...
std::map< uint32_t, std::string > OrcadReadHierarchyLinks(const std::vector< char > &aData, const std::vector< std::string > &aStrings, const ORCAD_WARN_FN &aWarn, std::map< uint32_t, std::string > *aOccurrenceRefs)
Parse a 'Views/<folder>/Hierarchy/Hierarchy' stream into block-instance links: block db id -> child f...
ORCAD_RAW_PAGE OrcadParsePageV2(const std::vector< char > &aData, const std::vector< std::string > &aStrings, const ORCAD_WARN_FN &)
Parse one v2.0 (pre-2003) 'Views/<folder>/Pages/<page>' stream.
void OrcadParseOlbPackageStreamV2(const std::vector< char > &aData, const std::vector< std::string > &aStrings, std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols, std::map< std::string, ORCAD_PACKAGE > &aPackages)
Parse one v2.0 .OLB 'Packages/<name>' stream (a part's inline symbol definitions plus its package/dev...
ORCAD_OCC_SCOPE OrcadReadOccurrenceTree(const std::vector< char > &aData, const ORCAD_WARN_FN &aWarn)
Parse the root folder 'Hierarchy/Hierarchy' stream into the full occurrence tree: per-scope part refe...
std::vector< std::string > OrcadParsePageOrder(const std::vector< char > &aData)
Parse the 'Views/<folder>/Schematic' stream and return the folder's page names in display order.
ORCAD_RAW_PAGE OrcadParsePage(const std::vector< char > &aData, const std::vector< std::string > &aStrings, const ORCAD_WARN_FN &aWarn)
Parse one 'Views/<folder>/Pages/<page>' stream into raw structure lists.
Parsers for the per-page streams 'Views/<folder>/Pages/<page>', the per-folder page-order stream 'Vie...
bool OrcadPageHasHierarchyBlocks(const ORCAD_RAW_PAGE &aPage)
True when the page contains hierarchical block instances (DrawnInstance, type 12).
Definition orcad_page.h:152
Plain data records produced by the OrCAD Capture DSN stream parsers and consumed by ORCAD_CONVERTER.
std::function< void(const wxString &aMsg)> ORCAD_WARN_FN
Warning sink shared by all parser entry points (recoverable-issue channel).
@ RPT_SEVERITY_WARNING
std::string OrcadNormalizeCfbName(const std::string &aName)
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
Everything parsed from one .DSN, as handed to ORCAD_CONVERTER.
ORCAD_LIBRARY_INFO library
ORCAD_OCC_SCOPE occurrenceRoot
Occurrence tree from the root folder Hierarchy stream.
std::map< std::string, ORCAD_SYMBOL_DEF > symbols
cache, keyed by cache name
bool hasHierarchyBlocks
std::map< std::string, ORCAD_PACKAGE > packages
keyed by package name
std::string name
design (root schematic) name
std::map< std::string, std::vector< ORCAD_RAW_PAGE > > childFolderPages
Child schematic folder pages, keyed by lower-cased folder name; instantiated once per hierarchical bl...
std::vector< ORCAD_RAW_PAGE > pages
root schematic folder pages
Structure type 12: a hierarchical block instance placed on a page.
std::string childName
child folder, when embedded
std::vector< std::string > strings
global string table
std::string schematicName
root schematic folder name
A hierarchical block occurrence: one placement of a child schematic folder on a parent page.
uint32_t targetDbId
type-12 drawn-instance dbId on the parent page
ORCAD_OCC_SCOPE scope
the child's occurrences under this path
std::string childFolder
child schematic folder name
One node of the design occurrence tree parsed from the root Hierarchy stream.
std::vector< ORCAD_OCC_BLOCK > blocks
hierarchical block occurrences
std::map< uint32_t, std::string > partRefs
type-13 dbId -> occurrence refdes
One parsed 'Views/<folder>/Pages/<page>' stream, raw structure lists in stream order.
std::vector< ORCAD_DRAWN_INSTANCE > blocks
hierarchical blocks (detection only)