35bool isPrimType(
int aType )
57bool isSymbolType(
int aTypeId )
77bool isKnownStructType( uint8_t aType )
79 static const std::array<bool, 256> known = []()
81 std::array<bool, 256>
table{};
83 for(
int t : { 2, 4, 6, 9, 10, 11, 12, 13, 16, 20, 21, 23, 24, 26, 27, 29, 31, 32, 33,
84 34, 35, 37, 38, 39, 48, 49, 52, 53, 55, 56, 57, 58, 59, 60, 61, 62, 64,
85 65, 66, 67, 68, 69, 75, 76, 77, 78, 82, 88, 89, 91, 98, 103 } )
97std::optional<ORCAD_PRIMITIVE> readPrimitiveBody(
ORCAD_STREAM& aStream,
int aType );
101std::optional<ORCAD_PRIMITIVE> readSymbolVector(
ORCAD_STREAM& aStream )
114 uint16_t count = aStream.
ReadU16();
116 for( uint16_t i = 0; i < count; i++ )
120 aStream.
ExpectByte( 0x00, wxS(
"symbol vector prim pad" ) );
121 int t2 = aStream.
ReadU8();
123 if( t != t2 || !isPrimType( t ) )
126 std::optional<ORCAD_PRIMITIVE> child;
131 child = readSymbolVector( aStream );
135 child = readPrimitiveBody( aStream, t );
139 group.children.push_back( std::move( *child ) );
150std::optional<ORCAD_PRIMITIVE> readPrimitiveBody(
ORCAD_STREAM& aStream,
int t1 )
153 size_t size = aStream.
ReadU32();
159 size_t end = start + size;
166 static const uint8_t
pad[4] = { 0x00, 0x00, 0x00, 0x00 };
167 aStream.
Expect(
pad, 4, wxS(
"primitive pad" ) );
169 size_t clen =
end - start;
171 std::optional<ORCAD_PRIMITIVE> prim;
193 prim = std::move( p );
210 prim = std::move( p );
238 prim = std::move( p );
243 size_t body = start + 8;
244 const uint8_t* data = aStream.
Data();
246 std::vector<size_t> candidates;
249 candidates = { 16, 8, 0 };
251 candidates = { 8, 0 };
256 for(
size_t candidate : candidates )
258 if( body + candidate + 2 > aStream.
Size() )
261 size_t n =
static_cast<size_t>( data[body + candidate] )
262 |
static_cast<size_t>( data[body + candidate + 1] ) << 8;
263 size_t need = 8 + candidate + 2 + 4 * n;
273 if( size == need - 8 )
275 end = start + size + 8;
283 THROW_IO_ERRORF( wxS(
"poly primitive at 0x%zx: no consistent point count for size %zu" ), start, size );
289 aStream.
Seek( body );
300 aStream.
Seek( body + off );
302 uint16_t pointCount = aStream.
ReadU16();
311 for( uint16_t i = 0; i < pointCount; i++ )
319 prim = std::move( p );
334 prim = std::move( p );
347 uint32_t dataSize = aStream.
ReadU32();
350 if( aStream.
GetOffset() +
static_cast<size_t>( dataSize ) <=
end )
353 prim = std::move( p );
367 size_t from = std::min( aStream.
GetOffset(), aStream.
Size() );
368 size_t to = std::min(
end, aStream.
Size() );
371 p.
data.assign( aStream.
Data() + from, aStream.
Data() + to );
373 prim = std::move( p );
389 int t1 = aStream.
ReadU8();
390 int t2 = aStream.
ReadU8();
392 if( t1 != t2 || !isPrimType( t1 ) )
396 return readSymbolVector( aStream );
398 return readPrimitiveBody( aStream, t1 );
407 if( stream.
PeekU8() == 0x00 )
427 uint32_t portType = stream.
ReadU32();
428 pin.portType = portType <= 7 ? static_cast<ORCAD_PORT_TYPE>( portType )
444 std::vector<size_t> stops = aPrefixes.
stops;
445 std::sort( stops.begin(), stops.end() );
455 uint16_t primCount = stream.
ReadU16();
457 for( uint16_t i = 0; i < primCount; i++ )
462 sym.
primitives.push_back( std::move( *prim ) );
465 if( i + 1 < primCount )
467 int b0 = stream.
PeekU8( 0 );
468 int b1 = stream.
PeekU8( 1 );
470 if( b0 >= 0 && b1 >= 0 && !( b0 == b1 && isPrimType( b0 ) ) )
476 auto nextStopIt = std::upper_bound( stops.begin(), stops.end(), stream.
GetOffset() );
478 if( nextStopIt != stops.end() )
480 size_t nextStop = *nextStopIt;
481 size_t gap = nextStop - stream.
GetOffset();
485 stream.
Seek( nextStop - 8 );
492 if( x1 <= x2 && y1 <= y2 && x2 - x1 <= 4000 && y2 - y1 <= 4000 )
504 stream.
Seek( nextStop );
510 uint16_t pinCount = stream.
ReadU16();
512 for( uint16_t i = 0; i < pinCount; i++ )
519 sym.
pins.push_back( std::move( *
pin ) );
523 uint16_t propCount = stream.
ReadU16();
525 for( uint16_t i = 0; i < propCount; i++ )
533 stream.
Seek( aPrefixes.
end - 2 );
562 uint32_t dbId = stream.
ReadU32();
595 block.
w = bbox.
x2 - bbox.
x1;
596 block.
h = bbox.
y2 - bbox.
y1;
600 std::vector<size_t> stops = aPrefixes.
stops;
601 std::sort( stops.begin(), stops.end() );
603 if( stops.size() >= 2 && stops[stops.size() - 2] >= stream.
GetOffset() )
604 stream.
Seek( stops[stops.size() - 2] );
610 uint16_t pinCount = stream.
ReadU16();
612 std::vector<ORCAD_PIN_INST> pinInsts;
614 for( uint16_t i = 0; i < pinCount; i++ )
619 pinInsts.push_back( std::move( *
pin ) );
622 for(
size_t i = 0; i < pinInsts.size() && i < nested.
pins.size(); i++ )
629 blockPin.
x = pinInsts[i].x;
630 blockPin.
y = pinInsts[i].y;
631 block.
pins.push_back( std::move( blockPin ) );
653 uint16_t pinCount = stream.
ReadU16();
655 for( uint16_t i = 0; i < pinCount; i++ )
658 static const uint8_t emptyMarker[2] = { 0xFF, 0xFF };
692 uint16_t deviceCount = stream.
ReadU16();
694 for( uint16_t i = 0; i < deviceCount; i++ )
708 const uint8_t* data = aStream.
Data();
709 size_t size = aStream.
Size();
712 for(
int propCount = 0; propCount < 40; propCount++ )
714 size_t shortLen = 3 + 8 *
static_cast<size_t>( propCount );
716 if( aPreamblePos < shortLen )
719 size_t shortPos = aPreamblePos - shortLen;
720 uint8_t type = data[shortPos];
722 if( !isKnownStructType( type ) )
725 int16_t count =
static_cast<int16_t
>(
static_cast<uint16_t
>( data[shortPos + 1] )
726 |
static_cast<uint16_t
>( data[shortPos + 2] ) << 8 );
728 if( count != propCount )
731 if( !( propCount == 0 && count == -1 ) )
743 if( data[q] == type && data[q + 5] == 0 && data[q + 6] == 0 && data[q + 7] == 0
744 && data[q + 8] == 0 )
776 for(
size_t i = 0; i < pfx.
bodyLens.size(); i++ )
778 size_t stop = p + 9 * i + 9 + pfx.
bodyLens[i];
797void OrcadParseCache(
const std::vector<char>& aData,
const std::vector<std::string>& aStrings,
798 const ORCAD_WARN_FN& aWarn, std::map<std::string, ORCAD_SYMBOL_DEF>& aSymbols,
799 std::map<std::string, ORCAD_PACKAGE>& aPackages )
817 pos = preamblePos + 4;
821 stream.
Seek( *start );
831 pos = preamblePos + 4;
840 if( isSymbolType( typeId ) )
846 auto it = aSymbols.find( sym.
name );
848 if( it == aSymbols.end() )
850 std::string key = sym.
name;
851 aSymbols.emplace( std::move( key ), std::move( sym ) );
855 it->second.variants.push_back( std::move( sym ) );
863 std::string key = pkg.
name;
864 aPackages.insert_or_assign( std::move( key ), std::move( pkg ) );
871 aWarn( wxString::Format( wxS(
"cache struct type %d at 0x%zx: %s" ), typeId,
875 if( pfx.
end != 0 && pfx.
end > preamblePos )
881 pos = preamblePos + 4;
886 if( parsed || ( pfx.
end != 0 && pfx.
end > preamblePos ) )
887 pos = std::max( stream.
GetOffset(), preamblePos + 4 );
889 pos = preamblePos + 4;
895 std::map<std::string, ORCAD_PACKAGE>& aPackages,
896 std::map<std::string, ORCAD_SYMBOL_DEF>&& aExtraSymbols,
897 std::map<std::string, ORCAD_PACKAGE>&& aExtraPackages )
899 for(
auto& [
name, sym] : aExtraSymbols )
901 auto it = aSymbols.find(
name );
903 if( it == aSymbols.end() )
905 aSymbols.emplace(
name, std::move( sym ) );
910 std::vector<ORCAD_SYMBOL_DEF> extraVariants = std::move( sym.variants );
911 sym.variants.clear();
913 it->second.variants.push_back( std::move( sym ) );
916 it->second.variants.push_back( std::move( variant ) );
920 for(
auto& [
name, pkg] : aExtraPackages )
921 aPackages.try_emplace(
name, std::move( pkg ) );
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString Problem() const
what was the problem?
Little-endian byte cursor over one OrCAD Capture DSN stream.
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.
void SkipOptionalPreambleBlock()
If the preamble sits at the cursor, consume it plus its u32 trailLen and the trailLen trailing bytes;...
static constexpr size_t npos
Returned by FindPreamble() when no further preamble exists.
bool HasPreambleAt(size_t aAbsoluteOffset) const
True when the preamble sits at the given absolute offset (false if out of range).
std::vector< uint8_t > ReadBytes(size_t aCount)
Read exactly aCount bytes; throws IO_ERROR on overrun.
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.
void ExpectByte(uint8_t aValue, const wxString &aWhat)
Consume one byte and require the given value.
void Expect(const uint8_t *aBytes, size_t aCount, const wxString &aWhat)
Consume aCount bytes and require them to equal aBytes; throws IO_ERROR naming aWhat and showing expec...
Stateful reader shared by all structure parsers.
std::map< std::string, std::string > PropsDict(const ORCAD_PREFIXES &aPrefixes) const
Resolve the short-prefix (nameIdx, valueIdx) pairs; empty names are dropped.
ORCAD_READ_RESULT ReadStructure()
Read one structure of any type: prefixes, then the type-specific body via the reader dispatch below.
ORCAD_PREFIXES TryReadPrefixes(int aCount)
Attempt to read exactly aCount prefixes (aCount - 1 long + 1 short) at the current position and verif...
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,...)
void OrcadMergeCacheStreams(std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols, std::map< std::string, ORCAD_PACKAGE > &aPackages, std::map< std::string, ORCAD_SYMBOL_DEF > &&aExtraSymbols, std::map< std::string, ORCAD_PACKAGE > &&aExtraPackages)
Merge the results of a 'Packages/<name>' stream (locally modified parts) into the main cache maps: a ...
ORCAD_DEVICE OrcadReadDevice(ORCAD_STRUCT_READER &aReader)
Read one Device structure (reads its own prefixes; type must be 32).
std::optional< ORCAD_SYMBOL_PIN > OrcadReadSymbolPin(ORCAD_STRUCT_READER &aReader)
Read one symbol pin.
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 ...
ORCAD_PACKAGE OrcadReadPackage(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Read a Package body (type 31); layout documented on ORCAD_PACKAGE.
ORCAD_DRAWN_INSTANCE OrcadReadDrawnInstance(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Structure type 12 (DrawnInstance): hierarchical block instance.
std::optional< ORCAD_PRIMITIVE > OrcadReadPrimitive(ORCAD_STREAM &aStream)
Read one graphic primitive including its doubled u8 type-pair prefix, at the current cursor.
void OrcadParseCache(const std::vector< char > &aData, const std::vector< std::string > &aStrings, const ORCAD_WARN_FN &aWarn, std::map< std::string, ORCAD_SYMBOL_DEF > &aSymbols, std::map< std::string, ORCAD_PACKAGE > &aPackages)
Scan a Cache-framed stream (the 'Cache' stream itself, or any 'Packages/<name>' stream — they share t...
ORCAD_SYMBOL_DEF OrcadReadSymbolDef(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes, bool aWithPins)
Read a symbol definition body (LibraryPart / GlobalSymbol / PortSymbol / OffPageSymbol / TitleBlockSy...
ORCAD_SYMBOL_DEF OrcadReadSthInPages0(ORCAD_STRUCT_READER &aReader, const ORCAD_PREFIXES &aPrefixes)
Structure type 2 (SthInPages0): nested symbol body inside Graphic*Inst structures on pages; carries t...
Parsers for the DSN 'Cache' stream and the 'Packages/<name>' streams: symbol definitions with graphic...
std::function< void(const wxString &aMsg)> ORCAD_WARN_FN
Warning sink shared by all parser entry points (recoverable-issue channel).
@ ORCAD_PRIM_COMMENT_TEXT
@ ORCAD_PRIM_BITMAP
plain DIB (BITMAPINFOHEADER + pixels)
@ ORCAD_PRIM_OLE_IMAGE
OLE compound document embed.
@ ORCAD_PRIM_SYMBOL_VECTOR
nested prefix-framed vector graphic
@ ORCAD_ST_TITLEBLOCK_SYMBOL
@ ORCAD_ST_SYMBOL_PIN_SCALAR
@ ORCAD_ST_GLOBAL_SYMBOL
power symbol definition
@ ORCAD_ST_BOOKMARK_SYMBOL
@ ORCAD_ST_SYMBOL_PIN_BUS
@ ORCAD_ST_OFFPAGE_SYMBOL
@ ORCAD_ST_PIN_SHAPE_SYMBOL
std::vector< ORCAD_DISPLAY_PROP > OrcadReadDisplayPropList(ORCAD_STRUCT_READER &aReader)
Read a u16-counted list of framed DisplayProp structures via ReadStructure(), keeping only the succes...
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
One interface pin of a hierarchical block, at its absolute page position.
One device of a package: the pin-number map of a unit (structure type 32).
std::vector< std::string > pinNumbers
std::vector< bool > pinIgnore
Structure type 12: a hierarchical block instance placed on a page.
int x1
block rectangle top-left, page DBU
std::vector< ORCAD_BLOCK_PIN > pins
std::vector< ORCAD_DISPLAY_PROP > displayProps
A package: refdes prefix, footprint and per-unit devices (structure type 31).
std::map< std::string, std::string > props
Part-level properties shared by every placement (Description, Tolerance, ...).
std::vector< ORCAD_DEVICE > devices
T0x10: one pin of a placed instance, carrying the pin's absolute page position (the connection point ...
Integer point in OrCAD DBU.
The decoded prefix chain of one framed structure.
std::vector< size_t > stops
checkpoint offsets, one per long prefix: start + 9 * i + 9 + bodyLens[i]
int typeId
ORCAD_ST value (u8 in the stream)
std::vector< uint32_t > bodyLens
one per long prefix, outermost first
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_POINT > points
polygon/polyline/bezier vertices
std::vector< uint8_t > data
kind == IMAGE: raw embedded payload
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.
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
std::map< std::string, std::string > props
int typeId
ORCAD_ST value.
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).
wxString result
Test unit parsing edge cases and error handling.