KiCad PCB EDA Suite
Loading...
Searching...
No Matches
orcad_page.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
24
25#include <algorithm>
26#include <optional>
27#include <utility>
28
29#include <ki_exception.h>
30
35
36
37namespace
38{
39
40template <typename T>
41bool takeRecord( ORCAD_READ_RESULT& aResult, std::vector<T>& aTarget )
42{
43 if( T* record = std::get_if<T>( &aResult.record ) )
44 {
45 aTarget.push_back( std::move( *record ) );
46 return true;
47 }
48
49 return false;
50}
51
52
53template <typename T>
54void readStructureList( ORCAD_STRUCT_READER& aReader, std::vector<T>& aTarget )
55{
56 uint16_t count = aReader.Stream().ReadU16();
57
58 for( uint16_t i = 0; i < count; i++ )
59 {
61 takeRecord( result, aTarget );
62 }
63}
64
65} // namespace
66
67
68ORCAD_RAW_PAGE OrcadParsePage( const std::vector<char>& aData,
69 const std::vector<std::string>& aStrings,
70 const ORCAD_WARN_FN& aWarn )
71{
72 ORCAD_STREAM stream( aData );
73 ORCAD_STRUCT_READER reader( stream, &aStrings, aWarn );
74 ORCAD_RAW_PAGE page;
75
76 ORCAD_PREFIXES prefixes = reader.ReadPrefixes();
77
78 if( prefixes.typeId != ORCAD_ST_PAGE )
79 {
80 THROW_IO_ERROR( wxString::Format( wxS( "OrCAD page stream: expected Page structure, "
81 "got type %d" ),
82 prefixes.typeId ) );
83 }
84
85 page.name = stream.ReadLzt();
86 page.pageSize = stream.ReadLzt();
87
89 page.width = settings.width;
90 page.height = settings.height;
91 page.isMetric = settings.isMetric;
92
93 readStructureList( reader, page.titleBlocks );
94
95 // T0x34/T0x35 raw (not prefix-framed); read only to stay aligned.
96 uint16_t count = stream.ReadU16();
97
98 for( uint16_t i = 0; i < count; i++ )
99 OrcadReadT0x34Raw( stream );
100
101 count = stream.ReadU16();
102
103 for( uint16_t i = 0; i < count; i++ )
104 OrcadReadT0x35Raw( stream );
105
106 // Net table = lzt net name + u32 net db id; authoritative for names/junctions, wires key it.
107 count = stream.ReadU16();
108
109 for( uint16_t i = 0; i < count; i++ )
110 {
111 std::string netName = stream.ReadLzt();
112 uint32_t netId = stream.ReadU32();
113
114 page.netmap[netId] = netName;
115 }
116
117 readStructureList( reader, page.wires );
118
119 // Placed parts; type 13 = part instance, type 12 = hier block instance.
120 count = stream.ReadU16();
121
122 for( uint16_t i = 0; i < count; i++ )
123 {
125
126 if( !takeRecord( result, page.instances ) )
127 takeRecord( result, page.blocks );
128 }
129
130 readStructureList( reader, page.ports );
131
132 // Each Global and OffPageConnector list entry followed by 5 bytes.
133 count = stream.ReadU16();
134
135 for( uint16_t i = 0; i < count; i++ )
136 {
138 takeRecord( result, page.globals );
139 stream.Skip( 5 );
140 }
141
142 count = stream.ReadU16();
143
144 for( uint16_t i = 0; i < count; i++ )
145 {
147 takeRecord( result, page.offpage );
148 stream.Skip( 5 );
149 }
150
151 readStructureList( reader, page.ercObjects );
152 readStructureList( reader, page.busEntries );
153 readStructureList( reader, page.graphics );
154
155 return page;
156}
157
158
159std::vector<std::string> OrcadParsePageOrder( const std::vector<char>& aData )
160{
161 ORCAD_STREAM stream( aData );
162 ORCAD_STRUCT_READER reader( stream );
163
164 reader.ReadPrefixes();
165
166 stream.ReadLzt(); // schematic folder name
167 stream.Skip( 4 );
168
169 uint16_t count = stream.ReadU16();
170
171 std::vector<std::string> names;
172 names.reserve( count );
173
174 for( uint16_t i = 0; i < count; i++ )
175 names.push_back( stream.ReadLzt() );
176
177 // Page names stored last-first; reverse to display order.
178 std::reverse( names.begin(), names.end() );
179
180 return names;
181}
182
183
184std::map<uint32_t, std::string> OrcadReadHierarchyLinks( const std::vector<char>& aData,
185 const std::vector<std::string>& aStrings,
186 const ORCAD_WARN_FN& aWarn,
187 std::map<uint32_t, std::string>*
188 aOccurrenceRefs )
189{
190 std::map<uint32_t, std::string> links;
191
192 ORCAD_STREAM stream( aData );
193 ORCAD_STRUCT_READER reader( stream, &aStrings, aWarn );
194
195 size_t pos = 0;
196
197 while( true )
198 {
199 size_t preamblePos = stream.FindPreamble( pos );
200
201 if( preamblePos == ORCAD_STREAM::npos )
202 break;
203
204 std::optional<size_t> start = OrcadFindStructureStart( stream, preamblePos );
205
206 if( !start.has_value() || stream.Data()[*start] != ORCAD_ST_HIERARCHY_LINK )
207 {
208 pos = preamblePos + 4;
209 continue;
210 }
211
212 stream.Seek( *start );
213
214 try
215 {
216 ORCAD_PREFIXES prefixes = reader.ReadPrefixes();
217
218 // Body u32, u32 inst db id, u8 inner-frame marker 0x42, u32, u32, lzt child folder name.
219 stream.ReadU32();
220 uint32_t instDbId = stream.ReadU32();
221
222 stream.ExpectByte( 0x42, wxS( "hierarchy link inner frame" ) );
223
224 stream.ReadU32();
225 stream.ReadU32();
226
227 // First lzt = child folder (hier block link), second lzt = occurrence refdes; either
228 // may be empty.
229 std::string child = stream.ReadLzt();
230 std::string occurrenceRef = stream.ReadLzt();
231
232 if( !child.empty() )
233 links[instDbId] = child;
234
235 if( aOccurrenceRefs && !occurrenceRef.empty() )
236 ( *aOccurrenceRefs )[instDbId] = occurrenceRef;
237
238 pos = std::max( stream.GetOffset(), preamblePos + 4 );
239
240 if( prefixes.end != 0 && prefixes.end > pos )
241 pos = prefixes.end;
242 }
243 catch( const IO_ERROR& )
244 {
245 pos = preamblePos + 4;
246 }
247 }
248
249 return links;
250}
251
252
253// Framed occ header = long prefix (u8 type, u32 bodyLen, u32 0) + short prefix (u8 type, i16
254// propCount, propCount x u32 pairs) + FF E4 5C 39 preamble; throw on mismatch to scan fallback.
255static uint8_t readOccHeader( ORCAD_STREAM& aStream, int aExpectType )
256{
257 uint8_t type = aStream.ReadU8();
258 aStream.ReadU32(); // bodyLen, unused
259
260 if( aStream.ReadU32() != 0 )
261 THROW_IO_ERROR( wxS( "occurrence record: long-prefix pad not zero" ) );
262
263 if( aStream.ReadU8() != type )
264 THROW_IO_ERROR( wxS( "occurrence record: short-prefix type mismatch" ) );
265
266 int16_t propCount = aStream.ReadI16();
267
268 for( int i = 0; i < std::max<int>( propCount, 0 ); i++ )
269 {
270 aStream.ReadU32();
271 aStream.ReadU32();
272 }
273
274 aStream.ExpectPreamble( wxS( "occurrence record preamble" ) );
275 aStream.Skip( aStream.ReadU32() ); // trailer
276
277 if( aExpectType >= 0 && type != aExpectType )
278 THROW_IO_ERROR( wxString::Format( wxS( "occurrence record type %d != expected %d" ),
279 (int) type, aExpectType ) );
280
281 return type;
282}
283
284
285static ORCAD_OCC_SCOPE readOccScope( ORCAD_STREAM& aStream );
286
287
288static void readOccurrence( ORCAD_STREAM& aStream, ORCAD_OCC_SCOPE& aScope )
289{
290 readOccHeader( aStream, 0x42 );
291
292 aStream.ReadU32(); // occurrence's own db id
293 uint32_t targetDbId = aStream.ReadU32(); // placed-instance (t13) / block (t12) db id
294
295 aStream.ExpectByte( 0x42, wxS( "occurrence inner marker" ) );
296
297 aStream.ReadU32(); // C (symbol-complexity correlated)
298 aStream.ReadU32(); // D (zero observed)
299
300 std::string child = aStream.ReadLzt(); // child folder name; empty for parts
301 std::string ref = aStream.ReadLzt(); // occurrence refdes; empty when none
302
303 aStream.ReadU32(); // F (zero except rare multi-unit)
304
305 uint16_t pinCount = aStream.ReadU16();
306
307 for( uint16_t i = 0; i < pinCount; i++ )
308 {
309 readOccHeader( aStream, -1 ); // 0x44 scalar / 0x45 bus pin occurrence
310 aStream.ReadU32(); // pin occurrence db id
311 aStream.ReadU16(); // pin index
312 }
313
314 ORCAD_OCC_SCOPE nested = readOccScope( aStream );
315
316 if( !child.empty() )
317 {
318 ORCAD_OCC_BLOCK block;
319 block.targetDbId = targetDbId;
320 block.childFolder = child;
321 block.scope = std::move( nested );
322 aScope.blocks.push_back( std::move( block ) );
323 }
324 else if( !ref.empty() )
325 {
326 aScope.partRefs[targetDbId] = ref;
327 }
328}
329
330
331// Scope = net occ (0x43), title-block occ (0x52), global/off-page occ (0x5b, u32-counted),
332// optional separator preamble, then part/block occ; only part/block kept, rest read to stay aligned.
334{
335 ORCAD_OCC_SCOPE scope;
336
337 uint16_t netCount = aStream.ReadU16();
338
339 for( uint16_t i = 0; i < netCount; i++ )
340 {
341 readOccHeader( aStream, 0x43 );
342 aStream.ReadU32();
343 aStream.ReadLzt();
344 }
345
346 uint16_t titleBlockCount = aStream.ReadU16();
347
348 for( uint16_t i = 0; i < titleBlockCount; i++ )
349 {
350 readOccHeader( aStream, 0x52 );
351 aStream.ReadU32();
352 aStream.ReadU32();
353 }
354
355 uint32_t globalCount = aStream.ReadU32();
356
357 for( uint32_t i = 0; i < globalCount; i++ )
358 {
359 readOccHeader( aStream, 0x5b );
360 aStream.ReadU32();
361 aStream.ReadU32();
362 }
363
364 if( aStream.AtPreamble() )
365 {
366 aStream.Skip( 4 );
367 aStream.Skip( aStream.ReadU32() );
368 }
369
370 uint16_t occCount = aStream.ReadU16();
371
372 for( uint16_t i = 0; i < occCount; i++ )
373 readOccurrence( aStream, scope );
374
375 return scope;
376}
377
378
379// v2.0 (pre-2003) page parsing. Short-prefix-only framing: every structure is u8 typeId, i16
380// propCount, propCount x (u16 nameIdx, u16 valueIdx), no long prefixes, no FF E4 5C 39 preambles.
381// String-table indices u16 (modern u32); primitive bodies drop doubled type/byteLength envelope.
382// Record vocabulary/field order otherwise modern. Modern path (version >= 3) untouched.
383
384static std::string v2Resolve( const std::vector<std::string>& aStrings, uint16_t aIdx )
385{
386 return ( aIdx != 0xFFFF && aIdx < aStrings.size() ) ? aStrings[aIdx] : std::string();
387}
388
389
390// Some ancient v2 OLB streams use 10-byte display-prop body (u8 dispMode, no u16, no terminator);
391// selected per stream by retry. thread_local so parallel library loads do not race on flag.
392static thread_local bool g_v2ShortDisplayProp = false;
393
394
395// Reject repeat count that cannot fit remaining bytes or exceeds ceiling, so mis-parsed count
396// throws (stream skipped) not runaway allocation.
397static void v2CheckCount( ORCAD_STREAM& aStream, uint32_t aCount )
398{
399 if( aCount > 30000 || aCount > aStream.Remaining() )
400 {
401 THROW_IO_ERROR( wxString::Format( wxS( "v2 repeat count %u exceeds the sane bound "
402 "(%zu bytes remain)" ),
403 aCount, aStream.Remaining() ) );
404 }
405}
406
407
408// v2 short prefix; fills aProps w/ resolved name/value pairs (empty value when index 0xFFFF).
409static uint8_t v2Prefix( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings,
410 std::map<std::string, std::string>* aProps = nullptr )
411{
412 uint8_t type = aStream.ReadU8();
413 int16_t count = aStream.ReadI16();
414
415 if( count > 1000 )
416 THROW_IO_ERROR( wxString::Format( wxS( "v2 prefix: absurd property count %d" ), count ) );
417
418 for( int i = 0; i < count; i++ )
419 {
420 uint16_t nameIdx = aStream.ReadU16();
421 uint16_t valueIdx = aStream.ReadU16();
422
423 if( aProps )
424 ( *aProps )[v2Resolve( aStrings, nameIdx )] = v2Resolve( aStrings, valueIdx );
425 }
426
427 return type;
428}
429
430
432 const std::vector<std::string>& aStrings )
433{
434 v2Prefix( aStream, aStrings );
435
437 prop.nameIdx = aStream.ReadU16();
438 prop.name = v2Resolve( aStrings, static_cast<uint16_t>( prop.nameIdx ) );
439 prop.x = aStream.ReadI16();
440 prop.y = aStream.ReadI16();
441
442 uint16_t rotFont = aStream.ReadU16();
443 prop.fontIdx = rotFont & 0x3FFF;
444 prop.rotation = ( rotFont >> 14 ) & 0x3;
445 prop.color = aStream.ReadU8();
446
448 {
449 prop.dispMode = aStream.ReadU8();
450 }
451 else
452 {
453 prop.dispMode = aStream.ReadU16();
454 aStream.ExpectByte( 0x00, wxS( "v2 display prop terminator" ) );
455 }
456
457 return prop;
458}
459
460
461static std::vector<ORCAD_DISPLAY_PROP> v2DisplayPropList( ORCAD_STREAM& aStream,
462 const std::vector<std::string>& aStrings )
463{
464 std::vector<ORCAD_DISPLAY_PROP> props;
465 uint16_t count = aStream.ReadU16();
466
467 for( uint16_t i = 0; i < count; i++ )
468 props.push_back( v2DisplayProp( aStream, aStrings ) );
469
470 return props;
471}
472
473
474static ORCAD_ALIAS v2Alias( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
475{
476 v2Prefix( aStream, aStrings );
477
478 ORCAD_ALIAS alias;
479 alias.x = aStream.ReadI32();
480 alias.y = aStream.ReadI32();
481 alias.color = aStream.ReadU32();
482 alias.rotation = aStream.ReadU32() & 0x3;
483 alias.fontIdx = aStream.ReadU32();
484 alias.name = aStream.ReadLzt();
485
486 return alias;
487}
488
489
490static void v2Structure( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings );
491
492
493static ORCAD_WIRE v2Wire( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
494{
495 uint8_t type = v2Prefix( aStream, aStrings );
496
497 ORCAD_WIRE wire;
498 aStream.ReadU32(); // wire db id
499 wire.id = aStream.ReadU32(); // net db id, keys page net table
500 wire.color = static_cast<int>( aStream.ReadU32() );
501 wire.x1 = aStream.ReadI32();
502 wire.y1 = aStream.ReadI32();
503 wire.x2 = aStream.ReadI32();
504 wire.y2 = aStream.ReadI32();
505 wire.isBus = type == ORCAD_ST_WIRE_BUS;
506 aStream.Skip( 1 );
507
508 uint16_t aliasCount = aStream.ReadU16();
509
510 for( uint16_t i = 0; i < aliasCount; i++ )
511 wire.aliases.push_back( v2Alias( aStream, aStrings ) );
512
513 uint16_t propCount = aStream.ReadU16();
514
515 for( uint16_t i = 0; i < propCount; i++ )
516 v2Structure( aStream, aStrings ); // framed wire properties, consumed in full
517
518 return wire;
519}
520
521
522static ORCAD_PIN_INST v2PinInst( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
523{
524 v2Prefix( aStream, aStrings );
525
527 aStream.ReadU16();
528 pin.x = aStream.ReadI16();
529 pin.y = aStream.ReadI16();
530 pin.wordA = aStream.ReadU32();
531 pin.wordB = aStream.ReadU32();
532 pin.displayProps = v2DisplayPropList( aStream, aStrings );
533
534 return pin;
535}
536
537
539 const std::vector<std::string>& aStrings )
540{
542 v2Prefix( aStream, aStrings, &inst.props );
543
544 aStream.Skip( 8 ); // uninitialized header bytes
545 inst.pkgName = aStream.ReadLzt();
546 inst.dbId = aStream.ReadU32();
547
548 int by1 = aStream.ReadI16();
549 int bx1 = aStream.ReadI16();
550 int by2 = aStream.ReadI16();
551 int bx2 = aStream.ReadI16();
552 inst.bbox.x1 = bx1;
553 inst.bbox.y1 = by1;
554 inst.bbox.x2 = bx2;
555 inst.bbox.y2 = by2;
556
557 inst.x = aStream.ReadI16();
558 inst.y = aStream.ReadI16();
559 inst.color = aStream.ReadU8();
560
561 uint8_t orientation = aStream.ReadU8();
562 inst.rotation = orientation & 0x3;
563 inst.mirror = ( orientation & 0x4 ) != 0;
564 aStream.Skip( 2 );
565
566 inst.displayProps = v2DisplayPropList( aStream, aStrings );
567 aStream.Skip( 1 );
568 inst.reference = aStream.ReadLzt();
569 inst.value = v2Resolve( aStrings, aStream.ReadU16() ); // v2 u16 value index
570 aStream.Skip( 6 ); // v2 6 bytes (modern 10)
571
572 uint16_t pinCount = aStream.ReadU16();
573
574 for( uint16_t i = 0; i < pinCount; i++ )
575 inst.pins.push_back( v2PinInst( aStream, aStrings ) );
576
577 inst.sourcePackage = aStream.ReadLzt();
578 aStream.Skip( 2 );
579
580 return inst;
581}
582
583
584static ORCAD_PRIMITIVE v2PrimBody( ORCAD_STREAM& aStream, uint8_t aType, int aDepth = 0 );
585
586
588{
589 return v2PrimBody( aStream, aStream.ReadU8() );
590}
591
592
594 const std::vector<std::string>& aStrings )
595{
596 v2Prefix( aStream, aStrings );
597
600 def.name = aStream.ReadLzt();
601 def.sourceLib = aStream.ReadLzt();
602 def.color = static_cast<int>( aStream.ReadU32() );
603
604 uint16_t primCount = aStream.ReadU16();
605
606 for( uint16_t i = 0; i < primCount; i++ )
607 def.primitives.push_back( v2Primitive( aStream ) );
608
609 ORCAD_BBOX bbox;
610 bbox.x1 = aStream.ReadI16();
611 bbox.y1 = aStream.ReadI16();
612 bbox.x2 = aStream.ReadI16();
613 bbox.y2 = aStream.ReadI16();
614 def.bbox = bbox;
615
616 return def;
617}
618
619
620static ORCAD_PRIMITIVE v2PrimBody( ORCAD_STREAM& aStream, uint8_t aType, int aDepth )
621{
622 // Symbol vectors nest recursively; bound depth so crafted chain cannot exhaust stack.
623 if( aDepth > 32 )
624 THROW_IO_ERROR( wxS( "v2 primitive nesting too deep" ) );
625
626 uint8_t type = aType;
627 ORCAD_PRIMITIVE prim;
628
629 switch( type )
630 {
631 case ORCAD_PRIM_RECT:
634 prim.x1 = aStream.ReadI32();
635 prim.y1 = aStream.ReadI32();
636 prim.x2 = aStream.ReadI32();
637 prim.y2 = aStream.ReadI32();
638 prim.lineStyle = aStream.ReadU32();
639 prim.lineWidth = aStream.ReadU32();
640 prim.fillStyle = aStream.ReadU32();
641 prim.hatchStyle = aStream.ReadU32();
642 break;
643
644 case ORCAD_PRIM_LINE:
646 prim.x1 = aStream.ReadI32();
647 prim.y1 = aStream.ReadI32();
648 prim.x2 = aStream.ReadI32();
649 prim.y2 = aStream.ReadI32();
650 prim.lineStyle = aStream.ReadU32();
651 prim.lineWidth = aStream.ReadU32();
652 break;
653
654 case ORCAD_PRIM_ARC:
656 prim.x1 = aStream.ReadI32();
657 prim.y1 = aStream.ReadI32();
658 prim.x2 = aStream.ReadI32();
659 prim.y2 = aStream.ReadI32();
660 prim.start = ORCAD_POINT{ aStream.ReadI32(), aStream.ReadI32() };
661 prim.end = ORCAD_POINT{ aStream.ReadI32(), aStream.ReadI32() };
662 prim.lineStyle = aStream.ReadU32();
663 prim.lineWidth = aStream.ReadU32();
664 break;
665
669 {
673 prim.lineStyle = aStream.ReadU32();
674 prim.lineWidth = aStream.ReadU32();
675
676 if( type == ORCAD_PRIM_POLYGON )
677 {
678 prim.fillStyle = aStream.ReadU32();
679 prim.hatchStyle = aStream.ReadU32();
680 }
681
682 uint16_t count = aStream.ReadU16();
683 v2CheckCount( aStream, count );
684
685 for( uint16_t i = 0; i < count; i++ )
686 {
687 int y = aStream.ReadI16(); // points are stored y-first
688 int x = aStream.ReadI16();
689 prim.points.push_back( ORCAD_POINT{ x, y } );
690 }
691
692 break;
693 }
694
696 {
697 // Nested graphic doubled type byte, prefix, i16 location, nested prims each padded (u8
698 // type, u8 0x00); flatten not meaningful, so read to stay aligned and drop.
699 aStream.ExpectByte( ORCAD_PRIM_SYMBOL_VECTOR, wxS( "v2 symbol vector pair" ) );
700
701 int16_t nProp = aStream.ReadI16();
702
703 for( int i = 0; i < std::max<int>( nProp, 0 ); i++ )
704 {
705 aStream.ReadU16();
706 aStream.ReadU16();
707 }
708
710 prim.x1 = aStream.ReadI16();
711 prim.y1 = aStream.ReadI16();
712
713 uint16_t nested = aStream.ReadU16();
714 v2CheckCount( aStream, nested );
715
716 for( uint16_t i = 0; i < nested; i++ )
717 {
718 uint8_t nestedType = aStream.ReadU8();
719 aStream.ExpectByte( 0x00, wxS( "v2 vector prim pad" ) );
720 prim.children.push_back( v2PrimBody( aStream, nestedType, aDepth + 1 ) );
721 }
722
723 aStream.ReadLzt(); // vector name
724 break;
725 }
726
729 prim.x1 = aStream.ReadI32();
730 prim.y1 = aStream.ReadI32();
731 aStream.ReadI32(); // x2
732 aStream.ReadI32(); // y2
733 aStream.ReadI32(); // x1 (duplicate corner)
734 aStream.ReadI32(); // y1
735 prim.fontIdx = aStream.ReadU16();
736 aStream.Skip( 2 );
737 prim.text = aStream.ReadLzt();
738 break;
739
740 default:
741 THROW_IO_ERROR( wxString::Format( wxS( "v2 primitive: unhandled type %d" ), (int) type ) );
742 }
743
744 return prim;
745}
746
747
749 const std::vector<std::string>& aStrings )
750{
752 inst.typeId = v2Prefix( aStream, aStrings, &inst.props );
753
754 uint16_t nameIdx = aStream.ReadU16();
755 aStream.ReadU16(); // source library string index
756 aStream.Skip( 4 ); // uninitialized junk
757 inst.logicalName = v2Resolve( aStrings, nameIdx );
758 inst.name = aStream.ReadLzt();
759 inst.dbId = aStream.ReadU32();
760
761 inst.y = aStream.ReadI16();
762 inst.x = aStream.ReadI16();
763 int y2 = aStream.ReadI16();
764 int x2 = aStream.ReadI16();
765 int x1 = aStream.ReadI16();
766 int y1 = aStream.ReadI16();
767 inst.bbox.x1 = x1;
768 inst.bbox.y1 = y1;
769 inst.bbox.x2 = x2;
770 inst.bbox.y2 = y2;
771
772 inst.color = aStream.ReadU8();
773 uint8_t orientation = aStream.ReadU8();
774 inst.rotation = orientation & 0x3;
775 inst.mirror = ( orientation & 0x4 ) != 0;
776 aStream.Skip( 2 );
777
778 inst.displayProps = v2DisplayPropList( aStream, aStrings );
779
780 uint8_t flag = aStream.ReadU8();
781
782 if( flag == 0x02 )
783 inst.nested = std::make_unique<ORCAD_SYMBOL_DEF>( v2SymbolDef( aStream, aStrings ) );
784
785 return inst;
786}
787
788
789static void v2Structure( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
790{
791 switch( aStream.PeekU8() )
792 {
793 case ORCAD_ST_STH_IN_PAGES0: v2SymbolDef( aStream, aStrings ); break;
794 case ORCAD_ST_SYMBOL_DISPLAY_PROP: v2DisplayProp( aStream, aStrings ); break;
795 case ORCAD_ST_ALIAS: v2Alias( aStream, aStrings ); break;
796 case ORCAD_ST_T0X10:
797 case ORCAD_ST_T0X11: v2PinInst( aStream, aStrings ); break;
798 case ORCAD_ST_PLACED_INSTANCE: v2PlacedInstance( aStream, aStrings ); break;
800 case ORCAD_ST_WIRE_BUS: v2Wire( aStream, aStrings ); break;
801 default:
802 THROW_IO_ERROR( wxString::Format( wxS( "v2 nested structure: unhandled type %d" ),
803 aStream.PeekU8() ) );
804 }
805}
806
807
808// -- v2.0 .OLB symbol-library streams -----------------------------------------------
809
810static ORCAD_PORT_TYPE v2PortType( uint32_t aRaw )
811{
812 return aRaw <= 7 ? static_cast<ORCAD_PORT_TYPE>( aRaw ) : ORCAD_PORT_TYPE::PASSIVE;
813}
814
815
816// One symbol pin (type 26 scalar / 27 bus); lone 0x00 = skipped slot
817static bool v2SymbolPin( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings,
818 ORCAD_SYMBOL_PIN& aOut )
819{
820 if( aStream.PeekU8() == 0x00 )
821 {
822 aStream.Skip( 1 );
823 return false;
824 }
825
826 uint8_t type = v2Prefix( aStream, aStrings );
827
828 aOut.name = aStream.ReadLzt();
829 aOut.startX = aStream.ReadI32();
830 aOut.startY = aStream.ReadI32();
831 aOut.hotptX = aStream.ReadI32();
832 aOut.hotptY = aStream.ReadI32();
833 aOut.shapeBits = aStream.ReadU16();
834 aStream.Skip( 2 );
835 aOut.portType = v2PortType( aStream.ReadU32() );
836 aStream.ExpectByte( type, wxS( "v2 pin type echo" ) );
837 aStream.Skip( 3 );
838
839 uint16_t dispCount = aStream.ReadU16();
840 v2CheckCount( aStream, dispCount );
841
842 for( uint16_t i = 0; i < dispCount; i++ )
843 v2DisplayProp( aStream, aStrings );
844
845 return true;
846}
847
848
849// Symbol-def body shared by Symbols streams and inline LibraryParts (read after prefix).
851 const std::vector<std::string>& aStrings, int aTypeId )
852{
854 def.typeId = aTypeId;
855 def.name = aStream.ReadLzt();
856 def.sourceLib = aStream.ReadLzt();
857 def.color = static_cast<int>( aStream.ReadU32() );
858
859 uint16_t primCount = aStream.ReadU16();
860 v2CheckCount( aStream, primCount );
861
862 for( uint16_t i = 0; i < primCount; i++ )
863 def.primitives.push_back( v2Primitive( aStream ) );
864
865 ORCAD_BBOX bbox;
866 bbox.x1 = aStream.ReadI16();
867 bbox.y1 = aStream.ReadI16();
868 bbox.x2 = aStream.ReadI16();
869 bbox.y2 = aStream.ReadI16();
870 def.bbox = bbox;
871
872 uint16_t pinCount = aStream.ReadU16();
873 v2CheckCount( aStream, pinCount );
874
875 for( uint16_t i = 0; i < pinCount; i++ )
876 {
878
879 if( v2SymbolPin( aStream, aStrings, pin ) )
880 def.pins.push_back( std::move( pin ) );
881 }
882
883 uint16_t dispCount = aStream.ReadU16();
884 v2CheckCount( aStream, dispCount );
885
886 for( uint16_t i = 0; i < dispCount; i++ )
887 v2DisplayProp( aStream, aStrings );
888
889 return def;
890}
891
892
893// One part cell (type 6); views + one inline LibraryPart per view w/ GeneralProperties tail.
895{
896 std::string name;
897 std::vector<ORCAD_SYMBOL_DEF> symbols;
898 std::vector<std::string> viewNames;
899 std::string refDesPrefix;
900};
901
902
903static V2_PART_CELL v2PartCell( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
904{
905 v2Prefix( aStream, aStrings ); // type 6
906
907 V2_PART_CELL cell;
908 cell.name = aStream.ReadLzt();
909 aStream.ReadLzt(); // source library
910
911 uint16_t viewCount = aStream.ReadU16();
912 v2CheckCount( aStream, viewCount );
913
914 for( uint16_t i = 0; i < viewCount; i++ )
915 cell.viewNames.push_back( aStream.ReadLzt() );
916
917 uint16_t symbolCount = aStream.ReadU16();
918 v2CheckCount( aStream, symbolCount );
919
920 for( uint16_t i = 0; i < symbolCount; i++ )
921 {
922 v2Prefix( aStream, aStrings ); // type 24 LibraryPart
923 ORCAD_SYMBOL_DEF def = v2LibSymbolDef( aStream, aStrings, ORCAD_ST_LIBRARY_PART );
924
925 aStream.ReadLzt(); // implementation path
926 aStream.ReadLzt(); // implementation (PSpice model)
927 cell.refDesPrefix = aStream.ReadLzt();
928 aStream.ReadLzt(); // part value
929 def.generalFlags = aStream.ReadU16(); // pin number/name visibility bits
930
931 cell.symbols.push_back( std::move( def ) );
932 }
933
934 return cell;
935}
936
937
938static ORCAD_DEVICE v2Device( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
939{
940 v2Prefix( aStream, aStrings ); // type 32
941
942 ORCAD_DEVICE dev;
943 dev.unitRef = aStream.ReadLzt();
944 dev.refDes = aStream.ReadLzt(); // part name selecting part cell
945
946 uint16_t pinCount = aStream.ReadU16();
947 v2CheckCount( aStream, pinCount );
948
949 static const uint8_t emptySlot[2] = { 0xFF, 0xFF };
950
951 for( uint16_t i = 0; i < pinCount; i++ )
952 {
953 if( aStream.PeekMatches( emptySlot, 2 ) )
954 {
955 aStream.Skip( 2 );
956 dev.pinNumbers.push_back( std::string() );
957 dev.pinIgnore.push_back( true );
958 continue;
959 }
960
961 dev.pinNumbers.push_back( aStream.ReadLzt() );
962 dev.pinIgnore.push_back( ( aStream.ReadU8() & 0x80 ) != 0 );
963 }
964
965 return dev;
966}
967
968
969static ORCAD_PACKAGE v2Package( ORCAD_STREAM& aStream, const std::vector<std::string>& aStrings )
970{
971 v2Prefix( aStream, aStrings ); // type 31
972
973 ORCAD_PACKAGE pkg;
974 pkg.name = aStream.ReadLzt();
975 pkg.sourceLib = aStream.ReadLzt();
976 pkg.refDes = aStream.ReadLzt();
977 aStream.ReadLzt(); // unknown
978 pkg.pcbFootprint = aStream.ReadLzt();
979
980 uint16_t deviceCount = aStream.ReadU16();
981 v2CheckCount( aStream, deviceCount );
982
983 for( uint16_t i = 0; i < deviceCount; i++ )
984 pkg.devices.push_back( v2Device( aStream, aStrings ) );
985
986 return pkg;
987}
988
989
990ORCAD_RAW_PAGE OrcadParsePageV2( const std::vector<char>& aData,
991 const std::vector<std::string>& aStrings,
992 const ORCAD_WARN_FN& /* aWarn */ )
993{
994 ORCAD_STREAM stream( aData );
995 ORCAD_RAW_PAGE page;
996
997 uint8_t type = v2Prefix( stream, aStrings );
998
999 if( type != ORCAD_ST_PAGE )
1000 THROW_IO_ERROR( wxString::Format( wxS( "v2 page: unexpected root type %d" ), (int) type ) );
1001
1002 page.name = stream.ReadLzt();
1003 page.pageSize = stream.ReadLzt();
1004
1005 ORCAD_PAGE_SETTINGS settings = OrcadParsePageSettings( stream );
1006 page.width = settings.width;
1007 page.height = settings.height;
1008 page.isMetric = settings.isMetric;
1009
1010 uint16_t titleBlockCount = stream.ReadU16();
1011
1012 for( uint16_t i = 0; i < titleBlockCount; i++ )
1013 {
1014 page.titleBlocks.push_back( v2GraphicInst( stream, aStrings ) );
1015 stream.Skip( 12 ); // title-block trailer
1016 }
1017
1018 uint16_t allNetCount = stream.ReadU16(); // every net on page (name empty)
1019
1020 for( uint16_t i = 0; i < allNetCount; i++ )
1021 {
1022 stream.ReadU32();
1023 stream.ReadLzt();
1024 }
1025
1026 uint16_t netGroupCount = stream.ReadU16();
1027
1028 for( uint16_t i = 0; i < netGroupCount; i++ )
1029 {
1031 group.id = stream.ReadU32();
1032 group.name = stream.ReadLzt();
1033
1034 uint16_t memberCount = stream.ReadU16();
1035 v2CheckCount( stream, memberCount );
1036
1037 for( uint16_t j = 0; j < memberCount; j++ )
1038 group.members.push_back( stream.ReadU32() );
1039
1040 page.netGroups.push_back( std::move( group ) );
1041 }
1042
1043 uint16_t netmapCount = stream.ReadU16();
1044
1045 for( uint16_t i = 0; i < netmapCount; i++ )
1046 {
1047 std::string netName = stream.ReadLzt();
1048 page.netmap[stream.ReadU32()] = netName;
1049 }
1050
1051 uint16_t wireCount = stream.ReadU16();
1052
1053 for( uint16_t i = 0; i < wireCount; i++ )
1054 page.wires.push_back( v2Wire( stream, aStrings ) );
1055
1056 uint16_t instanceCount = stream.ReadU16();
1057
1058 for( uint16_t i = 0; i < instanceCount; i++ )
1059 page.instances.push_back( v2PlacedInstance( stream, aStrings ) );
1060
1061 uint16_t portCount = stream.ReadU16();
1062
1063 for( uint16_t i = 0; i < portCount; i++ )
1064 {
1065 page.ports.push_back( v2GraphicInst( stream, aStrings ) );
1066 stream.Skip( 9 );
1067 }
1068
1069 uint16_t globalCount = stream.ReadU16();
1070
1071 for( uint16_t i = 0; i < globalCount; i++ )
1072 {
1073 page.globals.push_back( v2GraphicInst( stream, aStrings ) );
1074 stream.Skip( 5 );
1075 }
1076
1077 uint16_t offPageCount = stream.ReadU16();
1078
1079 for( uint16_t i = 0; i < offPageCount; i++ )
1080 {
1081 page.offpage.push_back( v2GraphicInst( stream, aStrings ) );
1082 stream.Skip( 5 );
1083 }
1084
1085 uint16_t ercCount = stream.ReadU16();
1086
1087 for( uint16_t i = 0; i < ercCount; i++ )
1088 {
1089 page.ercObjects.push_back( v2GraphicInst( stream, aStrings ) );
1090 stream.ReadLzt();
1091 stream.ReadLzt();
1092 stream.ReadLzt();
1093 }
1094
1095 uint16_t busEntryCount = stream.ReadU16();
1096
1097 for( uint16_t i = 0; i < busEntryCount; i++ )
1098 {
1099 v2Prefix( stream, aStrings );
1100 ORCAD_BUS_ENTRY entry;
1101 entry.color = stream.ReadU32();
1102 stream.Skip( 8 );
1103 entry.x1 = stream.ReadI32();
1104 entry.y1 = stream.ReadI32();
1105 entry.x2 = stream.ReadI32();
1106 entry.y2 = stream.ReadI32();
1107 page.busEntries.push_back( entry );
1108 }
1109
1110 uint16_t graphicCount = stream.ReadU16();
1111
1112 for( uint16_t i = 0; i < graphicCount; i++ )
1113 page.graphics.push_back( v2GraphicInst( stream, aStrings ) );
1114
1115 return page;
1116}
1117
1118
1119void OrcadParseOlbSymbolStreamV2( const std::vector<char>& aData,
1120 const std::vector<std::string>& aStrings,
1121 std::map<std::string, ORCAD_SYMBOL_DEF>& aSymbols )
1122{
1123 // Some ancient streams use 10-byte display-prop body; retry whole stream with short form when
1124 // normal parse does not consume it exactly.
1125 for( bool shortDisp : { false, true } )
1126 {
1127 g_v2ShortDisplayProp = shortDisp;
1128 ORCAD_STREAM stream( aData );
1129
1130 try
1131 {
1132 uint8_t type = v2Prefix( stream, aStrings );
1133 ORCAD_SYMBOL_DEF def = v2LibSymbolDef( stream, aStrings, type );
1134
1135 if( stream.Remaining() != 0 )
1136 THROW_IO_ERROR( wxS( "v2 symbol stream: trailing bytes" ) );
1137
1138 if( !def.name.empty() )
1139 aSymbols.emplace( def.name, std::move( def ) );
1140
1141 g_v2ShortDisplayProp = false;
1142 return;
1143 }
1144 catch( const IO_ERROR& )
1145 {
1146 if( shortDisp )
1147 {
1148 g_v2ShortDisplayProp = false;
1149 throw;
1150 }
1151 }
1152 }
1153}
1154
1155
1156void OrcadParseOlbPackageStreamV2( const std::vector<char>& aData,
1157 const std::vector<std::string>& aStrings,
1158 std::map<std::string, ORCAD_SYMBOL_DEF>& aSymbols,
1159 std::map<std::string, ORCAD_PACKAGE>& aPackages )
1160{
1161 for( bool shortDisp : { false, true } )
1162 {
1163 g_v2ShortDisplayProp = shortDisp;
1164 ORCAD_STREAM stream( aData );
1165
1166 try
1167 {
1168 uint16_t partCount = stream.ReadU16();
1169 v2CheckCount( stream, partCount );
1170 std::vector<V2_PART_CELL> cells;
1171
1172 for( uint16_t i = 0; i < partCount; i++ )
1173 cells.push_back( v2PartCell( stream, aStrings ) );
1174
1175 ORCAD_PACKAGE pkg = v2Package( stream, aStrings );
1176
1177 if( stream.Remaining() != 0 )
1178 THROW_IO_ERROR( wxS( "v2 package stream: trailing bytes" ) );
1179
1180 // Inline symbol keyed by view name ("7400.Normal"); view suffix later stripped to
1181 // part base.
1182 for( const V2_PART_CELL& cell : cells )
1183 {
1184 for( const ORCAD_SYMBOL_DEF& def : cell.symbols )
1185 {
1186 if( !def.name.empty() )
1187 aSymbols.emplace( def.name, def );
1188 }
1189
1190 if( pkg.refDes.empty() && !cell.refDesPrefix.empty() )
1191 pkg.refDes = cell.refDesPrefix;
1192 }
1193
1194 if( !pkg.name.empty() )
1195 aPackages.emplace( pkg.name, std::move( pkg ) );
1196
1197 g_v2ShortDisplayProp = false;
1198 return;
1199 }
1200 catch( const IO_ERROR& )
1201 {
1202 if( shortDisp )
1203 {
1204 g_v2ShortDisplayProp = false;
1205 throw;
1206 }
1207 }
1208 }
1209}
1210
1211
1212ORCAD_OCC_SCOPE OrcadReadOccurrenceTree( const std::vector<char>& aData,
1213 const ORCAD_WARN_FN& aWarn )
1214{
1215 // Modern streams open w/ type-0x42 long prefix (u8 0x42, u32 bodyLen, u32 0); legacy pre-preamble
1216 // streams start at view-name lzt with only instance-annotated refs, so empty tree is correct.
1217 if( aData.size() < 9 || (uint8_t) aData[0] != 0x42 || aData[5] || aData[6] || aData[7]
1218 || aData[8] )
1219 {
1220 return {};
1221 }
1222
1223 ORCAD_STREAM stream( aData );
1224
1225 try
1226 {
1227 stream.ReadU8(); // 0x42
1228 stream.ReadU32(); // bodyLen
1229 stream.ReadU32(); // 0
1230 stream.ReadLzt(); // view name
1231 stream.Skip( 9 ); // zeros
1232 return readOccScope( stream );
1233 }
1234 catch( const IO_ERROR& e )
1235 {
1236 aWarn( wxString::Format( wxS( "The design occurrence tree could not be fully read (%s); "
1237 "reference designators fall back to the placed instances." ),
1238 e.What() ) );
1239 return {};
1240 }
1241}
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()
Little-endian byte cursor over one OrCAD Capture DSN stream.
void ExpectPreamble(const wxString &aWhat)
Consume the 4 preamble bytes; throws IO_ERROR naming aWhat when absent.
size_t Remaining() const
Bytes left; 0 when the cursor is at or past the end.
int PeekU8(size_t aAhead=0) const
Peek one byte at cursor + aAhead without advancing.
size_t FindPreamble(size_t aFrom) const
Find the next preamble at or after the given absolute offset.
bool AtPreamble(size_t aAhead=0) const
True when the 4 preamble bytes FF E4 5C 39 sit at cursor + aAhead.
uint8_t ReadU8()
static constexpr size_t npos
Returned by FindPreamble() when no further preamble exists.
size_t GetOffset() const
uint16_t ReadU16()
void Skip(size_t aCount)
Advance the cursor; throws IO_ERROR when aCount exceeds the remaining bytes.
std::string ReadLzt()
Read a length-prefixed zero-terminated string: u16 length, length content bytes, then a mandatory 0x0...
const uint8_t * Data() const
Raw buffer access for scan-and-backtrack parsers (cache/hierarchy walkers).
bool PeekMatches(const uint8_t *aBytes, size_t aCount, size_t aAhead=0) const
Compare aCount bytes at cursor + aAhead against aBytes without advancing.
void Seek(size_t aOffset)
Set the absolute cursor position.
int32_t ReadI32()
void ExpectByte(uint8_t aValue, const wxString &aWhat)
Consume one byte and require the given value.
uint32_t ReadU32()
int16_t ReadI16()
Stateful reader shared by all structure parsers.
ORCAD_STREAM & Stream()
ORCAD_READ_RESULT ReadStructure()
Read one structure of any type: prefixes, then the type-specific body via the reader dispatch below.
ORCAD_PREFIXES ReadPrefixes()
Discover the prefix count by trial from 10 down to 1 (longest chain first), then consume the prefixes...
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::optional< size_t > OrcadFindStructureStart(const ORCAD_STREAM &aStream, size_t aPreamblePos)
Given the absolute position of a preamble magic, backtrack to find a valid prefix chain ending right ...
Parsers for the DSN 'Cache' stream and the 'Packages/<name>' streams: symbol definitions with graphic...
ORCAD_PAGE_SETTINGS OrcadParsePageSettings(ORCAD_STREAM &aStream)
Read one 156-byte PageSettings block at the current cursor (embedded both in the Library stream and i...
Parser for the DSN root 'Library' stream: format version, fonts, page settings and the global string ...
static ORCAD_PIN_INST v2PinInst(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static std::string v2Resolve(const std::vector< std::string > &aStrings, uint16_t aIdx)
static void v2Structure(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_PORT_TYPE v2PortType(uint32_t aRaw)
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,...
static ORCAD_OCC_SCOPE readOccScope(ORCAD_STREAM &aStream)
static ORCAD_DISPLAY_PROP v2DisplayProp(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_PACKAGE v2Package(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
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.
static ORCAD_SYMBOL_DEF v2LibSymbolDef(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings, int aTypeId)
static void v2CheckCount(ORCAD_STREAM &aStream, uint32_t aCount)
static ORCAD_SYMBOL_DEF v2SymbolDef(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_WIRE v2Wire(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_GRAPHIC_INST v2GraphicInst(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
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...
static ORCAD_PRIMITIVE v2Primitive(ORCAD_STREAM &aStream)
static V2_PART_CELL v2PartCell(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_ALIAS v2Alias(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
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...
static uint8_t v2Prefix(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings, std::map< std::string, std::string > *aProps=nullptr)
static uint8_t readOccHeader(ORCAD_STREAM &aStream, int aExpectType)
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.
static ORCAD_PLACED_INSTANCE v2PlacedInstance(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static bool v2SymbolPin(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings, ORCAD_SYMBOL_PIN &aOut)
static thread_local bool g_v2ShortDisplayProp
static void readOccurrence(ORCAD_STREAM &aStream, ORCAD_OCC_SCOPE &aScope)
static std::vector< ORCAD_DISPLAY_PROP > v2DisplayPropList(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
static ORCAD_DEVICE v2Device(ORCAD_STREAM &aStream, const std::vector< std::string > &aStrings)
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.
static ORCAD_PRIMITIVE v2PrimBody(ORCAD_STREAM &aStream, uint8_t aType, int aDepth=0)
Parsers for the per-page streams 'Views/<folder>/Pages/<page>', the per-folder page-order stream 'Vie...
std::function< void(const wxString &aMsg)> ORCAD_WARN_FN
Warning sink shared by all parser entry points (recoverable-issue channel).
@ ORCAD_PRIM_ARC
@ ORCAD_PRIM_BEZIER
@ ORCAD_PRIM_POLYLINE
@ ORCAD_PRIM_COMMENT_TEXT
@ ORCAD_PRIM_LINE
@ ORCAD_PRIM_ELLIPSE
@ ORCAD_PRIM_POLYGON
@ ORCAD_PRIM_RECT
@ ORCAD_PRIM_SYMBOL_VECTOR
nested prefix-framed vector graphic
ORCAD_PORT_TYPE
Pin electrical type codes (u32 portType field of a symbol pin).
@ ORCAD_ST_HIERARCHY_LINK
block dbId -> child folder link
@ ORCAD_ST_STH_IN_PAGES0
nested symbol body inside Graphic*Inst
@ ORCAD_ST_T0X10
scalar pin instance (absolute pos)
@ ORCAD_ST_WIRE_SCALAR
@ ORCAD_ST_PLACED_INSTANCE
@ ORCAD_ST_PAGE
@ ORCAD_ST_LIBRARY_PART
@ ORCAD_ST_ALIAS
net alias attached to a wire
@ ORCAD_ST_WIRE_BUS
@ ORCAD_ST_SYMBOL_DISPLAY_PROP
@ ORCAD_ST_T0X11
bus pin instance (absolute pos)
void OrcadReadT0x34Raw(ORCAD_STREAM &aStream)
T0x34 records are NOT prefix-framed.
void OrcadReadT0x35Raw(ORCAD_STREAM &aStream)
T0x35 = the T0x34 raw layout followed by u16 n and 4 * n bytes.
Prefix framing machinery and readers for the prefix-framed OrCAD structures found in Page/Cache/Schem...
Net alias attached to a wire (becomes a local label).
std::string name
int rotation
0..3 quarter turns
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
Bus entry (structure type 29).
int y1
int color
int x2
int y2
int x1
One device of a package: the pin-number map of a unit (structure type 32).
std::vector< std::string > pinNumbers
std::string refDes
std::vector< bool > pinIgnore
std::string unitRef
One displayed property of an instance (Part Reference, Value, user fields).
int fontIdx
1-based into ORCAD_LIBRARY_INFO::fonts; 0 = default
int rotation
0..3 quarter turns
std::string name
resolved property name (empty when index invalid)
Shared body of Port / Global / OffPageConnector / TitleBlock / ERCObject and the Graphic*Inst shapes ...
std::unique_ptr< ORCAD_SYMBOL_DEF > nested
SthInPages0 body, else nullptr.
std::map< std::string, std::string > props
int rotation
0..3 quarter turns
std::string name
cache symbol name
std::vector< ORCAD_DISPLAY_PROP > displayProps
std::string logicalName
ports: resolved net/port name
int typeId
ORCAD_ST value.
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
A package: refdes prefix, footprint and per-unit devices (structure type 31).
std::string refDes
std::string sourceLib
std::vector< ORCAD_DEVICE > devices
std::string pcbFootprint
std::string name
The 156-byte PageSettings block embedded in the Library stream and in every Page stream: 8 bytes crea...
T0x10: one pin of a placed instance, carrying the pin's absolute page position (the connection point ...
A placed part instance on a page (structure type 13).
std::string sourcePackage
package base name
std::vector< ORCAD_DISPLAY_PROP > displayProps
ORCAD_BBOX bbox
placed box, page DBU
int rotation
0..3 quarter turns
std::map< std::string, std::string > props
short-prefix property pairs
bool mirror
orientation bit 2
std::string value
resolved Part Value
std::vector< ORCAD_PIN_INST > pins
successfully parsed T0x10 records
Integer point in OrCAD DBU.
The decoded prefix chain of one framed structure.
int typeId
ORCAD_ST value (u8 in the stream)
size_t end
offset right after the whole structure (from the outermost long prefix); 0 when unknown
One graphic primitive of a symbol body or nested page graphic.
int fillStyle
0 solid, 1 none, 2 hatch pattern
std::string text
kind == TEXT
std::vector< ORCAD_PRIMITIVE > children
kind == GROUP, translated by (x1, y1)
std::vector< ORCAD_POINT > points
polygon/polyline/bezier vertices
ORCAD_PRIM_KIND kind
int lineStyle
0 solid, 1 dash, 2 dot, 3 dash-dot, 4 dash-dot-dot, 5 default
std::optional< ORCAD_POINT > start
arc start point
std::optional< ORCAD_POINT > end
arc end point
int lineWidth
Capture width enum: 0 thin, 1 medium, 2 wide, 3 default.
One parsed 'Views/<folder>/Pages/<page>' stream, raw structure lists in stream order.
std::vector< ORCAD_GRAPHIC_INST > ports
std::string name
std::vector< ORCAD_GRAPHIC_INST > globals
placed power symbols
std::map< uint32_t, std::string > netmap
net db id -> net name
std::vector< ORCAD_WIRE > wires
uint32_t width
mils, or um when isMetric
std::vector< ORCAD_NET_GROUP > netGroups
bus net id -> member net ids
std::vector< ORCAD_DRAWN_INSTANCE > blocks
hierarchical blocks (detection only)
std::vector< ORCAD_PLACED_INSTANCE > instances
std::vector< ORCAD_GRAPHIC_INST > graphics
free comment text/shapes/images
std::vector< ORCAD_GRAPHIC_INST > offpage
off-page connectors
std::vector< ORCAD_GRAPHIC_INST > titleBlocks
std::vector< ORCAD_BUS_ENTRY > busEntries
std::string pageSize
page-size name string, e.g. "B"
std::vector< ORCAD_GRAPHIC_INST > ercObjects
no-connect markers
ORCAD_RECORD_VARIANT record
A symbol definition from the design Cache (LibraryPart / GlobalSymbol / PortSymbol / OffPageSymbol / ...
std::string name
cache name, e.g. "C.Normal"
std::vector< ORCAD_SYMBOL_PIN > pins
std::vector< ORCAD_PRIMITIVE > primitives
int typeId
ORCAD_ST value.
std::string sourceLib
std::optional< ORCAD_BBOX > bbox
symbol-space body box
int generalFlags
LibraryPart GeneralProperties flags (-1 = absent); bit0 = pin numbers visible, bit2 = pin names hidde...
One pin of a symbol definition (structure types 26/27).
ORCAD_PORT_TYPE portType
One wire or bus segment.
uint32_t id
bool isBus
true for structure type 21
std::vector< ORCAD_ALIAS > aliases
std::vector< std::string > viewNames
std::string refDesPrefix
std::string name
std::vector< ORCAD_SYMBOL_DEF > symbols
one per view, keyed positionally
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.