KiCad PCB EDA Suite
Loading...
Searching...
No Matches
orcad_structures.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 <limits>
26#include <memory>
27#include <utility>
28#include <variant>
29
30#include <ki_exception.h>
31#include <wx/log.h>
32
34
35
36ORCAD_STRUCT_READER::ORCAD_STRUCT_READER( ORCAD_STREAM& aStream, const std::vector<std::string>* aStrings,
37 ORCAD_WARN_FN aWarn, ORCAD_DIALECT aDialect ) :
38 m_stream( aStream ),
39 m_strings( aStrings ),
40 m_warn( std::move( aWarn ) ),
41 m_dialect( aDialect )
42{
43}
44
45
46void ORCAD_STRUCT_READER::Warn( const wxString& aMsg ) const
47{
48 if( m_warn )
49 m_warn( aMsg );
50}
51
52
53std::optional<size_t> OrcadLongPrefixCount( int aTypeId )
54{
55 switch( aTypeId )
56 {
57 case 9:
58 case 66:
59 case 67:
60 case 68:
61 case 69:
62 case 82:
63 case 91: return 1;
64
65 case 10:
66 case 16:
67 case 17:
68 case 20:
69 case 21:
70 case 26:
71 case 27:
72 case 29:
73 case 32:
74 case 37:
75 case 38:
76 case 39:
77 case 48:
78 case 49:
79 case 55:
80 case 56:
81 case 57:
82 case 58:
83 case 59:
84 case 60:
85 case 61:
86 case 62:
87 case 88:
88 case 89: return 2;
89
90 case 2:
91 case 6:
92 case 12:
93 case 23:
94 case 31:
95 case 65:
96 case 77: return 3;
97
98 case 13:
99 case 33:
100 case 34:
101 case 35:
102 case 64:
103 case 75:
104 case 76: return 4;
105
106 case 24: return 5;
107
108 default: return std::nullopt;
109 }
110}
111
112
114{
115 ORCAD_PREFIXES pfx;
116 pfx.start = m_stream.GetOffset();
117 pfx.typeId = m_stream.ReadU8();
118
119 if( aExpectedType >= 0 && pfx.typeId != aExpectedType )
120 THROW_IO_ERRORF( wxS( "OrCAD structure: expected type %d, got %d" ), aExpectedType, pfx.typeId );
121
122 int16_t propertyCount = m_stream.ReadI16();
123
124 if( propertyCount > 1000 )
125 THROW_IO_ERRORF( wxS( "OrCAD legacy prefix: absurd property count %d" ), propertyCount );
126
127 for( int i = 0; i < propertyCount; ++i )
128 {
129 uint32_t nameIdx = m_stream.ReadU16();
130 uint32_t valueIdx = m_stream.ReadU16();
131 pfx.props.emplace_back( nameIdx, valueIdx );
132 }
133
134 pfx.bodyStart = m_stream.GetOffset();
135
136 return pfx;
137}
138
139
140ORCAD_PREFIXES ORCAD_STRUCT_READER::ReadPrefixes( int aExpectedType, size_t aEnclosingEnd, size_t aLongPrefixCount )
141{
142 if( m_dialect.legacy )
143 return readLegacyPrefix( aExpectedType );
144
145 ORCAD_PREFIXES pfx;
146 pfx.start = m_stream.GetOffset();
147
148 int typeId = m_stream.PeekU8();
149
150 if( typeId < 0 )
151 THROW_IO_ERROR( wxS( "OrCAD structure: missing structure type" ) );
152
153 if( aExpectedType >= 0 && typeId != aExpectedType )
154 THROW_IO_ERRORF( wxS( "OrCAD structure: expected type %d, got %d" ), aExpectedType, typeId );
155
156 std::optional<size_t> longCount = aLongPrefixCount == ORCAD_STREAM::npos
157 ? OrcadLongPrefixCount( typeId )
158 : std::optional<size_t>( aLongPrefixCount );
159
160 if( !longCount )
161 THROW_IO_ERRORF( wxS( "OrCAD structure: unregistered structure type %d" ), typeId );
162
163 if( *longCount == 0 )
164 THROW_IO_ERROR( wxS( "OrCAD structure: long prefix count is zero" ) );
165
166 size_t bound = aEnclosingEnd == ORCAD_STREAM::npos ? m_stream.Size() : aEnclosingEnd;
167
168 if( bound > m_stream.Size() )
169 THROW_IO_ERROR( wxS( "OrCAD structure: enclosing bound exceeds stream" ) );
170
171 for( size_t i = 0; i < *longCount; ++i )
172 {
173 int prefixType = m_stream.ReadU8();
174
175 if( prefixType != typeId )
176 THROW_IO_ERRORF( wxS( "OrCAD structure: prefix type mismatch %d != %d" ), prefixType, typeId );
177
178 pfx.bodyLens.push_back( m_stream.ReadU32() );
179
180 if( m_stream.ReadU32() != 0 )
181 THROW_IO_ERROR( wxS( "OrCAD structure: long prefix pad not zero" ) );
182 }
183
184 if( m_stream.ReadU8() != typeId )
185 THROW_IO_ERROR( wxS( "OrCAD structure: short prefix type mismatch" ) );
186
187 // Short prefix i16 pair count, then (u32 nameIdx, u32 valueIdx) pairs. Negative count = no pairs.
188 int16_t propertyCount = m_stream.ReadI16();
189
190 for( int i = 0; i < propertyCount; ++i )
191 {
192 uint32_t nameIdx = m_stream.ReadU32();
193 uint32_t valueIdx = m_stream.ReadU32();
194 pfx.props.emplace_back( nameIdx, valueIdx );
195 }
196
197 m_stream.ExpectPreamble( wxS( "structure preamble" ) );
198 uint32_t trail = m_stream.ReadU32();
199 m_stream.Skip( trail );
200 pfx.bodyStart = m_stream.GetOffset();
201 pfx.typeId = typeId;
202
203 for( size_t i = 0; i < pfx.bodyLens.size(); ++i )
204 {
205 // Body length counts bytes after own 9-byte record; outermost bounds whole structure.
206 size_t headerEnd = pfx.start + 9 * i + 9;
207
208 if( pfx.bodyLens[i] > std::numeric_limits<size_t>::max() - headerEnd )
209 THROW_IO_ERROR( wxS( "OrCAD structure: structure stop overflow" ) );
210
211 size_t stop = headerEnd + pfx.bodyLens[i];
212
213 if( stop < pfx.bodyStart || stop > bound )
214 THROW_IO_ERRORF( wxS( "OrCAD structure: stop 0x%zx outside the enclosing bound" ), stop );
215
216 pfx.stops.push_back( stop );
217 }
218
219 pfx.end = pfx.stops.front();
220
221 return pfx;
222}
223
224
226{
227 return m_dialect.legacy ? m_stream.ReadU16() : m_stream.ReadU32();
228}
229
230
232{
233 uint16_t count = m_stream.ReadU16();
234
235 if( m_dialect.legacy && ( count > 30000 || count > m_stream.Remaining() ) )
236 {
237 THROW_IO_ERRORF( wxS( "OrCAD legacy repeat count %u exceeds the sane bound (%zu bytes remain)" ), count,
238 m_stream.Remaining() );
239 }
240
241 return count;
242}
243
244
245std::string ORCAD_STRUCT_READER::Resolve( uint32_t aIndex ) const
246{
247 if( m_dialect.legacy && aIndex == 0xFFFF )
248 return std::string();
249
250 if( m_strings && aIndex < m_strings->size() )
251 return ( *m_strings )[aIndex];
252
253 return std::string();
254}
255
256
257std::map<std::string, std::string> ORCAD_STRUCT_READER::PropsDict( const ORCAD_PREFIXES& aPrefixes ) const
258{
259 std::map<std::string, std::string> out;
260
261 for( const std::pair<uint32_t, uint32_t>& prop : aPrefixes.props )
262 {
263 std::string name = Resolve( prop.first );
264
265 // Legacy imports have always kept empty-named properties
266 if( !name.empty() || m_dialect.legacy )
267 out[name] = Resolve( prop.second );
268 }
269
270 return out;
271}
272
273
274void ORCAD_STRUCT_READER::SkipStructure( const ORCAD_PREFIXES& aPrefixes, const wxString& aWhat )
275{
276 if( aPrefixes.end != 0 && aPrefixes.end >= m_stream.GetOffset() )
277 {
278 m_stream.Seek( aPrefixes.end );
279 }
280 else
281 {
282 THROW_IO_ERRORF( wxS( "OrCAD structure: cannot skip structure %s" ), aWhat );
283 }
284}
285
286
288{
289 ORCAD_STREAM::NEST_GUARD guard( m_stream, wxS( "structure" ) );
290
291 size_t start = m_stream.GetOffset();
293
295 result.typeId = pfx.typeId;
296
297 try
298 {
299 ORCAD_STREAM::LIMIT_GUARD limit( m_stream, pfx.end ? pfx.end : m_stream.Size() );
300
301 switch( pfx.typeId )
302 {
304 case ORCAD_ST_WIRE_BUS: result.record = OrcadReadWire( *this, pfx ); break;
305
306 case ORCAD_ST_ALIAS: result.record = OrcadReadAlias( *this, pfx ); break;
307
308 case ORCAD_ST_SYMBOL_DISPLAY_PROP: result.record = OrcadReadDisplayProp( *this, pfx ); break;
309
310 case ORCAD_ST_PLACED_INSTANCE: result.record = OrcadReadPlacedInstance( *this, pfx ); break;
311
312 case ORCAD_ST_PORT:
315 result.record = OrcadReadGraphicInst( *this, pfx );
316
317 // The seek below skips these trailers in modern records; legacy ones have no end to seek to
318 if( m_dialect.legacy && pfx.typeId == ORCAD_ST_ERC_OBJECT )
319 {
320 m_stream.ReadLzt();
321 m_stream.ReadLzt();
322 m_stream.ReadLzt();
323 }
324 else if( m_dialect.legacy )
325 {
326 m_stream.Skip( pfx.typeId == ORCAD_ST_PORT ? 9 : 12 );
327 }
328
329 break;
330
331 case ORCAD_ST_GLOBAL:
342 case ORCAD_ST_GRAPHIC_OLE_INST: result.record = OrcadReadGraphicInst( *this, pfx ); break;
343
345
346 case ORCAD_ST_T0X10:
347 case ORCAD_ST_T0X11: result.record = OrcadReadPinInst( *this, pfx ); break;
348
349 case ORCAD_ST_STH_IN_PAGES0: result.record = OrcadReadSymbolDef( *this, pfx, false ); break;
350
351 case ORCAD_ST_DRAWN_INSTANCE: result.record = OrcadReadDrawnInstance( *this, pfx ); break;
352
353 default:
354 // Nothing bounds a legacy record, so an unknown one cannot be skipped
355 if( m_dialect.legacy )
356 THROW_IO_ERRORF( wxS( "OrCAD legacy structure: unhandled type %d" ), pfx.typeId );
357
358 break;
359 }
360 }
361 catch( const IO_ERROR& e )
362 {
363 // Recover via prefix offsets on body-parse failure; one bad record must not abort page/cache parse.
364 if( pfx.end != 0 && pfx.end > start )
365 {
366 Warn( wxString::Format( wxS( "OrCAD structure type %d at 0x%zx: %s; skipped" ), pfx.typeId, start,
367 e.What() ) );
368 m_stream.Seek( pfx.end );
369 result.record = std::monostate();
370 return result;
371 }
372
373 throw;
374 }
375
376 // Port, title-block and ERC trailers and pin padding sit inside the frame undecoded
377 if( m_stream.GetOffset() < pfx.end )
378 {
379 if( !std::holds_alternative<std::monostate>( result.record ) )
380 {
381 wxLogTrace( wxS( "KICAD_ORCAD_IO" ), wxS( "OrCAD structure type %d at 0x%zx: %zu bytes not decoded" ),
382 pfx.typeId, start, pfx.end - m_stream.GetOffset() );
383 }
384
385 m_stream.Seek( pfx.end );
386 }
387
388 return result;
389}
390
391
392// -- per-type body readers ----------------------------------------------------------------
393
394
396{
397 ORCAD_STREAM& ds = aReader.Stream();
399
400 prop.nameIdx = aReader.ReadStrIdx();
401 prop.name = aReader.Resolve( prop.nameIdx );
402 prop.x = ds.ReadI16();
403 prop.y = ds.ReadI16();
404
405 // u16 bits 0..13 = 1-based font index, bits 14..15 = quarter turns.
406 uint16_t rotFont = ds.ReadU16();
407 prop.fontIdx = rotFont & 0x3FFF;
408 prop.rotation = ( rotFont >> 14 ) & 0x3;
409
410 // Version 1 bodies store no display mode; 0x100 shows the value
411 if( aReader.Dialect().shortDisplayProp )
412 {
413 ds.ReadU8();
414 prop.color = ds.ReadU8();
415 prop.dispMode = 0x100;
416 }
417 else
418 {
419 prop.color = ds.ReadU8();
420 prop.dispMode = ds.ReadU16();
421 ds.ExpectByte( 0x00, wxS( "display prop tail" ) );
422 }
423
424 return prop;
425}
426
427
429{
430 ORCAD_STREAM& ds = aReader.Stream();
431 ORCAD_ALIAS alias;
432
433 alias.x = ds.ReadI32();
434 alias.y = ds.ReadI32();
435 alias.color = static_cast<int>( ds.ReadU32() );
436 alias.rotation = static_cast<int>( ds.ReadU32() & 0x3 );
437 alias.fontIdx = static_cast<int>( ds.ReadU32() );
438 alias.name = ds.ReadLzt();
439
440 return alias;
441}
442
443
445{
446 ORCAD_STREAM& ds = aReader.Stream();
447 ORCAD_WIRE wire;
448
449 wire.dbId = ds.ReadU32();
450 wire.id = ds.ReadU32();
451 wire.color = static_cast<int>( ds.ReadU32() );
452 wire.x1 = ds.ReadI32();
453 wire.y1 = ds.ReadI32();
454 wire.x2 = ds.ReadI32();
455 wire.y2 = ds.ReadI32();
456 ds.Skip( 1 );
457
458 uint16_t aliasCount = ds.ReadU16();
459
460 for( int i = 0; i < aliasCount; i++ )
461 {
462 ORCAD_READ_RESULT r = aReader.ReadStructure();
463
464 if( ORCAD_ALIAS* alias = std::get_if<ORCAD_ALIAS>( &r.record ) )
465 wire.aliases.push_back( std::move( *alias ) );
466 }
467
468 uint16_t propCount = ds.ReadU16();
469
470 for( int i = 0; i < propCount; i++ )
471 aReader.ReadStructure();
472
473 if( !aReader.Dialect().legacy )
474 {
475 wire.lineWidth = static_cast<int>( ds.ReadU32() );
476 wire.lineStyle = static_cast<int>( ds.ReadU32() );
477 }
478
479 wire.isBus = ( aPrefixes.typeId == ORCAD_ST_WIRE_BUS );
480
481 return wire;
482}
483
484
486{
487 ORCAD_STREAM& ds = aReader.Stream();
489
490 aReader.ReadStrIdx();
491 inst.sourceLibrary = aReader.Resolve( aReader.ReadStrIdx() );
492
493 if( aReader.Dialect().legacy )
494 ds.Skip( 4 ); // uninitialized
495
496 inst.pkgName = ds.ReadLzt();
497 inst.dbId = ds.ReadU32();
498
499 // Placed bbox stored y-first; includes displayed text.
500 int by1 = ds.ReadI16();
501 int bx1 = ds.ReadI16();
502 int by2 = ds.ReadI16();
503 int bx2 = ds.ReadI16();
504 inst.bbox.x1 = bx1;
505 inst.bbox.y1 = by1;
506 inst.bbox.x2 = bx2;
507 inst.bbox.y2 = by2;
508
509 inst.x = ds.ReadI16();
510 inst.y = ds.ReadI16();
511 inst.color = ds.ReadU8();
512
513 // Orientation byte bits 0..1 = quarter turns, bit 2 = mirror.
514 uint8_t orientation = ds.ReadU8();
515 inst.rotation = orientation & 0x3;
516 inst.mirror = ( orientation & 0x4 ) != 0;
517
518 inst.partIndex = ds.ReadU8();
519 inst.partByte = ds.ReadU8();
520
521 inst.displayProps = OrcadReadDisplayPropList( aReader );
522
523 ds.Skip( 1 );
524 inst.reference = ds.ReadLzt();
525
526 // Part Value = string-table index after reference; next 10 bytes (legacy 6) unknown
527 inst.value = aReader.Resolve( aReader.ReadStrIdx() );
528 ds.Skip( aReader.Dialect().legacy ? 6 : 10 );
529
530 uint16_t pinCount = ds.ReadU16();
531
532 for( int i = 0; i < pinCount; i++ )
533 {
534 ORCAD_READ_RESULT r = aReader.ReadStructure();
535
536 if( ORCAD_PIN_INST* pin = std::get_if<ORCAD_PIN_INST>( &r.record ) )
537 inst.pins.push_back( std::move( *pin ) );
538 }
539
540 inst.sourcePackage = ds.ReadLzt();
541 inst.unitIndex = ds.ReadU16();
542
543 inst.props = aReader.PropsDict( aPrefixes );
544
545 return inst;
546}
547
548
550{
551 ORCAD_STREAM& ds = aReader.Stream();
553
554 uint32_t nameIdx = aReader.ReadStrIdx(); // logical net/port name string index (ports)
555 uint32_t sourceLibraryIdx = aReader.ReadStrIdx();
556
557 if( aReader.Dialect().legacy )
558 ds.Skip( 4 ); // uninitialized
559
560 inst.name = ds.ReadLzt();
561 inst.dbId = ds.ReadU32();
562
563 // Anchor and bbox stored interleaved: y, x, y2, x2, x1, y1.
564 inst.y = ds.ReadI16();
565 inst.x = ds.ReadI16();
566 int y2 = ds.ReadI16();
567 int x2 = ds.ReadI16();
568 int x1 = ds.ReadI16();
569 int y1 = ds.ReadI16();
570 inst.bbox.x1 = x1;
571 inst.bbox.y1 = y1;
572 inst.bbox.x2 = x2;
573 inst.bbox.y2 = y2;
574
575 inst.color = ds.ReadU8();
576
577 // Orientation byte bits 0..1 = quarter turns, bit 2 = mirror.
578 uint8_t orientation = ds.ReadU8();
579 inst.rotation = orientation & 0x3;
580 inst.mirror = ( orientation & 0x4 ) != 0;
581
582 ds.Skip( 2 ); // structId, unknown
583
584 inst.displayProps = OrcadReadDisplayPropList( aReader );
585
586 // Flag 0x02 = one nested structure, usually SthInPages0 symbol body with drawable primitives.
587 uint8_t flag = ds.ReadU8();
588
589 if( flag == 0x02 )
590 {
591 ORCAD_READ_RESULT nested = aReader.ReadStructure();
592
593 if( ORCAD_SYMBOL_DEF* def = std::get_if<ORCAD_SYMBOL_DEF>( &nested.record ) )
594 inst.nested = std::make_unique<ORCAD_SYMBOL_DEF>( std::move( *def ) );
595 }
596
597 inst.typeId = aPrefixes.typeId;
598 inst.props = aReader.PropsDict( aPrefixes );
599 inst.logicalName = aReader.Resolve( nameIdx );
600
601 // Only the legacy reader ever kept the source library
602 if( std::string sourceLibrary = aReader.Resolve( sourceLibraryIdx );
603 aReader.Dialect().legacy && !sourceLibrary.empty() )
604 {
605 inst.props["Source Library"] = std::move( sourceLibrary );
606 }
607
608 return inst;
609}
610
611
613{
614 ORCAD_STREAM& ds = aReader.Stream();
616
617 pin.pinIndex = ds.ReadI16();
618 pin.x = ds.ReadI16();
619 pin.y = ds.ReadI16();
620 pin.wordA = ds.ReadU32();
621 pin.wordB = ds.ReadU32();
622 pin.displayProps = OrcadReadDisplayPropList( aReader );
623
624 return pin;
625}
626
627
629{
630 ORCAD_BUS_ENTRY entry;
631
632 entry.color = static_cast<int>( aStream.ReadU32() );
633 entry.x1 = aStream.ReadI32();
634 entry.y1 = aStream.ReadI32();
635 entry.x2 = aStream.ReadI32();
636 entry.y2 = aStream.ReadI32();
637 aStream.Skip( 8 );
638
639 return entry;
640}
641
642
643std::vector<ORCAD_DISPLAY_PROP> OrcadReadDisplayPropList( ORCAD_STRUCT_READER& aReader )
644{
645 std::vector<ORCAD_DISPLAY_PROP> out;
646
647 uint16_t count = aReader.ReadCount();
648
649 for( int i = 0; i < count; i++ )
650 {
651 ORCAD_READ_RESULT r = aReader.ReadStructure();
652
653 if( ORCAD_DISPLAY_PROP* prop = std::get_if<ORCAD_DISPLAY_PROP>( &r.record ) )
654 out.push_back( std::move( *prop ) );
655 }
656
657 return out;
658}
659
660
662{
663 ORCAD_NET_GROUP net;
664
665 aStream.Skip( 9 );
666 net.id = aStream.ReadU32();
667 net.name = aStream.ReadLzt();
668 aStream.ReadU32();
669 aStream.ReadU32(); // color
670 aStream.ReadU32(); // line style
671 aStream.ReadU32(); // line width
672
673 return net;
674}
675
676
678{
679 ORCAD_NET_GROUP net = OrcadReadT0x34Raw( aStream );
680
681 uint16_t count = aStream.ReadU16();
682
683 for( uint16_t i = 0; i < count; ++i )
684 net.members.push_back( aStream.ReadU32() );
685
686 return net;
687}
const char * name
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()
Limit reads to one record so a malformed body cannot consume the next record.
Bound shared parser recursion; entering a level above MAX_NESTING throws IO_ERROR.
The caller owns the buffer.
uint8_t ReadU8()
– scalars (little-endian, bounds-checked, throw IO_ERROR on overrun) ----—
static constexpr size_t npos
Generic invalid offset sentinel.
uint16_t ReadU16()
void Skip(size_t aCount)
Advance the cursor; throws IO_ERROR when aCount exceeds the remaining bytes.
std::string ReadLzt()
– strings ----------------------------------------------------------------—
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()
ReadStructure can recover from a body error when the prefix supplies a valid end offset.
std::map< std::string, std::string > PropsDict(const ORCAD_PREFIXES &aPrefixes) const
Resolve the short-prefix (nameIdx, valueIdx) pairs.
void SkipStructure(const ORCAD_PREFIXES &aPrefixes, const wxString &aWhat)
Throws IO_ERROR if the end is unknown or behind the cursor.
ORCAD_PREFIXES ReadPrefixes(int aExpectedType=-1, size_t aEnclosingEnd=ORCAD_STREAM::npos, size_t aLongPrefixCount=ORCAD_STREAM::npos)
aLongPrefixCount overrides the type depth; aEnclosingEnd bounds all stops.
const ORCAD_DIALECT & Dialect() const
ORCAD_STREAM & Stream()
uint32_t ReadStrIdx()
A string-table index in the dialect's width.
void Warn(const wxString &aMsg) const
Report a recoverable problem to the warning sink (no-op when none was given).
std::string Resolve(uint32_t aIndex) const
String-table lookup; returns "" for out-of-range indices and the legacy sentinel.
uint16_t ReadCount()
A u16 list count.
ORCAD_READ_RESULT ReadStructure()
Always resumes at the prefix end, skipping unknown bodies and undecoded trailers.
const std::vector< std::string > * m_strings
ORCAD_PREFIXES readLegacyPrefix(int aExpectedType)
ORCAD_STREAM & m_stream
ORCAD_STRUCT_READER(ORCAD_STREAM &aStream, const std::vector< std::string > *aStrings=nullptr, ORCAD_WARN_FN aWarn=nullptr, ORCAD_DIALECT aDialect={})
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
STL namespace.
ORCAD_DRAWN_INSTANCE OrcadReadDrawnInstance(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
ORCAD_SYMBOL_DEF OrcadReadSymbolDef(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes, bool aWithPins)
Read a symbol definition body (LibraryPart / GlobalSymbol / PortSymbol / OffPageSymbol / TitleBlockSy...
Parsers for the DSN 'Cache' stream and the 'Packages/<name>' streams: symbol definitions with graphic...
std::function< void(const wxString &aMsg)> ORCAD_WARN_FN
Coordinates use DBU with Y down.
@ 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_GRAPHIC_ARC_INST
@ ORCAD_ST_DRAWN_INSTANCE
hierarchical block instance
@ ORCAD_ST_TITLEBLOCK
@ ORCAD_ST_GLOBAL
placed power symbol
@ ORCAD_ST_GRAPHIC_BITMAP_INST
@ ORCAD_ST_OFFPAGE_CONNECTOR
@ ORCAD_ST_PORT
@ ORCAD_ST_GRAPHIC_LINE_INST
@ ORCAD_ST_GRAPHIC_COMMENT_TEXT_INST
@ ORCAD_ST_GRAPHIC_ELLIPSE_INST
@ ORCAD_ST_GRAPHIC_BOX_INST
@ ORCAD_ST_ERC_OBJECT
saved design-rule-check marker
@ ORCAD_ST_GRAPHIC_POLYLINE_INST
@ ORCAD_ST_GRAPHIC_BEZIER_INST
@ ORCAD_ST_GRAPHIC_POLYGON_INST
@ 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)
@ ORCAD_ST_BUS_ENTRY
@ ORCAD_ST_GRAPHIC_OLE_INST
ORCAD_WIRE OrcadReadWire(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Types 20 (wire) and 21 (bus); isBus is set from the prefix type.
ORCAD_PLACED_INSTANCE OrcadReadPlacedInstance(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
std::vector< ORCAD_DISPLAY_PROP > OrcadReadDisplayPropList(ORCAD_STRUCT_READER &aReader)
Keep only display properties that ReadStructure decodes.
ORCAD_NET_GROUP OrcadReadT0x34Raw(ORCAD_STREAM &aStream)
T0x34 records have no prefixes; consume their fixed layout to preserve alignment.
ORCAD_DISPLAY_PROP OrcadReadDisplayProp(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &)
Body readers start after the prefixes.
ORCAD_BUS_ENTRY OrcadReadBusEntryBody(ORCAD_STREAM &aStream)
ORCAD_ALIAS OrcadReadAlias(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &)
ORCAD_GRAPHIC_INST OrcadReadGraphicInst(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Common body of Port/Global/OffPageConnector/TitleBlock/ERCObject/Graphic*Inst.
std::optional< size_t > OrcadLongPrefixCount(int aTypeId)
Registered number of long prefixes for a modern framed structure type.
ORCAD_PIN_INST OrcadReadPinInst(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &)
ORCAD_NET_GROUP OrcadReadT0x35Raw(ORCAD_STREAM &aStream)
T0x35 = the T0x34 raw layout followed by u16 n and 4 * n bytes.
ORCAD_WIRE OrcadReadWire(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Types 20 (wire) and 21 (bus); isBus is set from the prefix type.
ORCAD_PLACED_INSTANCE OrcadReadPlacedInstance(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
ORCAD_PIN_INST OrcadReadPinInst(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
ORCAD_DISPLAY_PROP OrcadReadDisplayProp(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Body readers start after the prefixes.
ORCAD_BUS_ENTRY OrcadReadBusEntryBody(ORCAD_STREAM &aStream)
ORCAD_GRAPHIC_INST OrcadReadGraphicInst(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Common body of Port/Global/OffPageConnector/TitleBlock/ERCObject/Graphic*Inst.
ORCAD_ALIAS OrcadReadAlias(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
std::optional< size_t > OrcadLongPrefixCount(int aTypeId)
Registered number of long prefixes for a modern framed structure type.
The owning wire defines the connection.
std::string name
int rotation
0..3 quarter turns
int y1
int color
int x2
int y2
int x1
Legacy (pre-v3) files have short prefixes only, u16 string indices with a 0xFFFF sentinel and nested ...
Display positions use symbol coordinates; rotFont combines the font index and quarter turns.
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)
Free graphics use nested primitive coordinates.
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.
std::vector< uint32_t > members
std::string name
Pin positions are absolute page connection points.
The placed box includes displayed text.
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
uint16_t unitIndex
zero-based package device index
std::map< std::string, std::string > props
short-prefix property pairs
bool mirror
orientation bit 2
std::string sourceLibrary
source library path from the placed-instance header
std::string value
resolved Part Value
std::vector< ORCAD_PIN_INST > pins
successfully parsed T0x10 records
Prefix lengths supply structure bounds.
std::vector< size_t > stops
< (from the outermost long prefix); < 0 when unknown
int typeId
ORCAD_ST value (u8 in the stream)
size_t bodyStart
offset right after the preamble trail
std::vector< std::pair< uint32_t, uint32_t > > props
short prefix (nameIdx, valueIdx) pairs
std::vector< uint32_t > bodyLens
one per long prefix, outermost first
size_t end
offset right after the whole structure
size_t start
stream offset where the chain began
ORCAD_RECORD_VARIANT record
The bounding box occupies the final eight bytes before the next prefix stop.
The wire ID refers to the page net table.
uint32_t id
uint32_t dbId
bool isBus
true for structure type 21
std::vector< ORCAD_ALIAS > aliases
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.