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