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;
284 THROW_IO_ERROR( wxString::Format( wxS(
"poly primitive at 0x%zx: no consistent "
285 "point count for size %zu" ),
293 aStream.
Seek( body );
304 aStream.
Seek( body + off );
306 uint16_t pointCount = aStream.
ReadU16();
315 for( uint16_t i = 0; i < pointCount; i++ )
323 prim = std::move( p );
338 prim = std::move( p );
351 uint32_t dataSize = aStream.
ReadU32();
354 if( aStream.
GetOffset() +
static_cast<size_t>( dataSize ) <=
end )
357 prim = std::move( p );
371 size_t from = std::min( aStream.
GetOffset(), aStream.
Size() );
372 size_t to = std::min(
end, aStream.
Size() );
375 p.
data.assign( aStream.
Data() + from, aStream.
Data() + to );
377 prim = std::move( p );
382 THROW_IO_ERROR( wxString::Format( wxS(
"primitive type %d overran (0x%zx > 0x%zx)" ), t1,
396 int t1 = aStream.
ReadU8();
397 int t2 = aStream.
ReadU8();
399 if( t1 != t2 || !isPrimType( t1 ) )
402 wxString::Format( wxS(
"bad primitive prefix %d/%d at 0x%zx" ), t1, t2, aStream.
GetOffset() - 2 ) );
406 return readSymbolVector( aStream );
408 return readPrimitiveBody( aStream, t1 );
417 if( stream.
PeekU8() == 0x00 )
437 uint32_t portType = stream.
ReadU32();
438 pin.portType = portType <= 7 ? static_cast<ORCAD_PORT_TYPE>( portType )
454 std::vector<size_t> stops = aPrefixes.
stops;
455 std::sort( stops.begin(), stops.end() );
465 uint16_t primCount = stream.
ReadU16();
467 for( uint16_t i = 0; i < primCount; i++ )
472 sym.
primitives.push_back( std::move( *prim ) );
475 if( i + 1 < primCount )
477 int b0 = stream.
PeekU8( 0 );
478 int b1 = stream.
PeekU8( 1 );
480 if( b0 >= 0 && b1 >= 0 && !( b0 == b1 && isPrimType( b0 ) ) )
486 auto nextStopIt = std::upper_bound( stops.begin(), stops.end(), stream.
GetOffset() );
488 if( nextStopIt != stops.end() )
490 size_t nextStop = *nextStopIt;
491 size_t gap = nextStop - stream.
GetOffset();
495 stream.
Seek( nextStop - 8 );
502 if( x1 <= x2 && y1 <= y2 && x2 - x1 <= 4000 && y2 - y1 <= 4000 )
514 stream.
Seek( nextStop );
520 uint16_t pinCount = stream.
ReadU16();
522 for( uint16_t i = 0; i < pinCount; i++ )
529 sym.
pins.push_back( std::move( *
pin ) );
533 uint16_t propCount = stream.
ReadU16();
535 for( uint16_t i = 0; i < propCount; i++ )
543 stream.
Seek( aPrefixes.
end - 2 );
572 uint32_t dbId = stream.
ReadU32();
592 THROW_IO_ERROR( wxString::Format( wxS(
"drawn instance nested flag %d at 0x%zx" ),
605 block.
w = bbox.
x2 - bbox.
x1;
606 block.
h = bbox.
y2 - bbox.
y1;
610 std::vector<size_t> stops = aPrefixes.
stops;
611 std::sort( stops.begin(), stops.end() );
613 if( stops.size() >= 2 && stops[stops.size() - 2] >= stream.
GetOffset() )
614 stream.
Seek( stops[stops.size() - 2] );
620 uint16_t pinCount = stream.
ReadU16();
622 std::vector<ORCAD_PIN_INST> pinInsts;
624 for( uint16_t i = 0; i < pinCount; i++ )
629 pinInsts.push_back( std::move( *
pin ) );
632 for(
size_t i = 0; i < pinInsts.size() && i < nested.
pins.size(); i++ )
639 blockPin.
x = pinInsts[i].x;
640 blockPin.
y = pinInsts[i].y;
641 block.
pins.push_back( std::move( blockPin ) );
663 uint16_t pinCount = stream.
ReadU16();
665 for( uint16_t i = 0; i < pinCount; i++ )
668 static const uint8_t emptyMarker[2] = { 0xFF, 0xFF };
702 uint16_t deviceCount = stream.
ReadU16();
704 for( uint16_t i = 0; i < deviceCount; i++ )
716 const uint8_t* data = aStream.
Data();
717 size_t size = aStream.
Size();
720 for(
int propCount = 0; propCount < 40; propCount++ )
722 size_t shortLen = 3 + 8 *
static_cast<size_t>( propCount );
724 if( aPreamblePos < shortLen )
727 size_t shortPos = aPreamblePos - shortLen;
728 uint8_t type = data[shortPos];
730 if( !isKnownStructType( type ) )
733 int16_t count =
static_cast<int16_t
>(
static_cast<uint16_t
>( data[shortPos + 1] )
734 |
static_cast<uint16_t
>( data[shortPos + 2] ) << 8 );
736 if( count != propCount )
739 if( !( propCount == 0 && count == -1 ) )
751 if( data[q] == type && data[q + 5] == 0 && data[q + 6] == 0 && data[q + 7] == 0
752 && data[q + 8] == 0 )
784 for(
size_t i = 0; i < pfx.
bodyLens.size(); i++ )
786 size_t stop = p + 9 * i + 9 + pfx.
bodyLens[i];
805void OrcadParseCache(
const std::vector<char>& aData,
const std::vector<std::string>& aStrings,
806 const ORCAD_WARN_FN& aWarn, std::map<std::string, ORCAD_SYMBOL_DEF>& aSymbols,
807 std::map<std::string, ORCAD_PACKAGE>& aPackages )
825 pos = preamblePos + 4;
829 stream.
Seek( *start );
839 pos = preamblePos + 4;
848 if( isSymbolType( typeId ) )
854 auto it = aSymbols.find( sym.
name );
856 if( it == aSymbols.end() )
858 std::string key = sym.
name;
859 aSymbols.emplace( std::move( key ), std::move( sym ) );
863 it->second.variants.push_back( std::move( sym ) );
871 std::string key = pkg.
name;
872 aPackages.insert_or_assign( std::move( key ), std::move( pkg ) );
879 aWarn( wxString::Format( wxS(
"cache struct type %d at 0x%zx: %s" ), typeId,
883 if( pfx.
end != 0 && pfx.
end > preamblePos )
889 pos = preamblePos + 4;
894 if( parsed || ( pfx.
end != 0 && pfx.
end > preamblePos ) )
895 pos = std::max( stream.
GetOffset(), preamblePos + 4 );
897 pos = preamblePos + 4;
903 std::map<std::string, ORCAD_PACKAGE>& aPackages,
904 std::map<std::string, ORCAD_SYMBOL_DEF>&& aExtraSymbols,
905 std::map<std::string, ORCAD_PACKAGE>&& aExtraPackages )
907 for(
auto& [
name, sym] : aExtraSymbols )
909 auto it = aSymbols.find(
name );
911 if( it == aSymbols.end() )
913 aSymbols.emplace(
name, std::move( sym ) );
918 std::vector<ORCAD_SYMBOL_DEF> extraVariants = std::move( sym.variants );
919 sym.variants.clear();
921 it->second.variants.push_back( std::move( sym ) );
924 it->second.variants.push_back( std::move( variant ) );
928 for(
auto& [
name, pkg] : aExtraPackages )
929 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
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::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 numbers visible, bit2 = pin names hidde...
One pin of a symbol definition (structure types 26/27).
std::vector< std::vector< std::string > > table
wxString result
Test unit parsing edge cases and error handling.