108 default:
return std::nullopt;
119 if( aExpectedType >= 0 && pfx.
typeId != aExpectedType )
122 int16_t propertyCount =
m_stream.ReadI16();
124 if( propertyCount > 1000 )
125 THROW_IO_ERRORF( wxS(
"OrCAD legacy prefix: absurd property count %d" ), propertyCount );
127 for(
int i = 0; i < propertyCount; ++i )
129 uint32_t nameIdx =
m_stream.ReadU16();
130 uint32_t valueIdx =
m_stream.ReadU16();
131 pfx.
props.emplace_back( nameIdx, valueIdx );
151 THROW_IO_ERROR( wxS(
"OrCAD structure: missing structure type" ) );
153 if( aExpectedType >= 0 && typeId != aExpectedType )
154 THROW_IO_ERRORF( wxS(
"OrCAD structure: expected type %d, got %d" ), aExpectedType, typeId );
158 : std::optional<size_t>( aLongPrefixCount );
161 THROW_IO_ERRORF( wxS(
"OrCAD structure: unregistered structure type %d" ), typeId );
163 if( *longCount == 0 )
164 THROW_IO_ERROR( wxS(
"OrCAD structure: long prefix count is zero" ) );
169 THROW_IO_ERROR( wxS(
"OrCAD structure: enclosing bound exceeds stream" ) );
171 for(
size_t i = 0; i < *longCount; ++i )
175 if( prefixType != typeId )
176 THROW_IO_ERRORF( wxS(
"OrCAD structure: prefix type mismatch %d != %d" ), prefixType, typeId );
181 THROW_IO_ERROR( wxS(
"OrCAD structure: long prefix pad not zero" ) );
185 THROW_IO_ERROR( wxS(
"OrCAD structure: short prefix type mismatch" ) );
188 int16_t propertyCount =
m_stream.ReadI16();
190 for(
int i = 0; i < propertyCount; ++i )
192 uint32_t nameIdx =
m_stream.ReadU32();
193 uint32_t valueIdx =
m_stream.ReadU32();
194 pfx.
props.emplace_back( nameIdx, valueIdx );
197 m_stream.ExpectPreamble( wxS(
"structure preamble" ) );
198 uint32_t trail =
m_stream.ReadU32();
203 for(
size_t i = 0; i < pfx.
bodyLens.size(); ++i )
206 size_t headerEnd = pfx.
start + 9 * i + 9;
208 if( pfx.
bodyLens[i] > std::numeric_limits<size_t>::max() - headerEnd )
209 THROW_IO_ERROR( wxS(
"OrCAD structure: structure stop overflow" ) );
211 size_t stop = headerEnd + pfx.
bodyLens[i];
213 if( stop < pfx.bodyStart || stop > bound )
214 THROW_IO_ERRORF( wxS(
"OrCAD structure: stop 0x%zx outside the enclosing bound" ), stop );
216 pfx.
stops.push_back( stop );
233 uint16_t count =
m_stream.ReadU16();
237 THROW_IO_ERRORF( wxS(
"OrCAD legacy repeat count %u exceeds the sane bound (%zu bytes remain)" ), count,
247 if(
m_dialect.legacy && aIndex == 0xFFFF )
248 return std::string();
250 if(
m_strings && aIndex < m_strings->size() )
253 return std::string();
259 std::map<std::string, std::string> out;
261 for(
const std::pair<uint32_t, uint32_t>& prop : aPrefixes.
props )
282 THROW_IO_ERRORF( wxS(
"OrCAD structure: cannot skip structure %s" ), aWhat );
291 size_t start =
m_stream.GetOffset();
364 if( pfx.
end != 0 && pfx.
end > start )
366 Warn( wxString::Format( wxS(
"OrCAD structure type %d at 0x%zx: %s; skipped" ), pfx.
typeId, start,
369 result.record = std::monostate();
379 if( !std::holds_alternative<std::monostate>(
result.record ) )
381 wxLogTrace( wxS(
"KICAD_ORCAD_IO" ), wxS(
"OrCAD structure type %d at 0x%zx: %zu bytes not decoded" ),
406 uint16_t rotFont = ds.
ReadU16();
407 prop.
fontIdx = rotFont & 0x3FFF;
408 prop.
rotation = ( rotFont >> 14 ) & 0x3;
421 ds.
ExpectByte( 0x00, wxS(
"display prop tail" ) );
458 uint16_t aliasCount = ds.
ReadU16();
460 for(
int i = 0; i < aliasCount; i++ )
465 wire.
aliases.push_back( std::move( *alias ) );
468 uint16_t propCount = ds.
ReadU16();
470 for(
int i = 0; i < propCount; i++ )
514 uint8_t orientation = ds.
ReadU8();
516 inst.
mirror = ( orientation & 0x4 ) != 0;
530 uint16_t pinCount = ds.
ReadU16();
532 for(
int i = 0; i < pinCount; i++ )
537 inst.
pins.push_back( std::move( *
pin ) );
555 uint32_t sourceLibraryIdx = aReader.
ReadStrIdx();
578 uint8_t orientation = ds.
ReadU8();
580 inst.
mirror = ( orientation & 0x4 ) != 0;
594 inst.
nested = std::make_unique<ORCAD_SYMBOL_DEF>( std::move( *def ) );
602 if( std::string sourceLibrary = aReader.
Resolve( sourceLibraryIdx );
605 inst.
props[
"Source Library"] = std::move( sourceLibrary );
645 std::vector<ORCAD_DISPLAY_PROP> out;
649 for(
int i = 0; i < count; i++ )
654 out.push_back( std::move( *prop ) );
681 uint16_t count = aStream.
ReadU16();
683 for( uint16_t i = 0; i < count; ++i )
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.
void Skip(size_t aCount)
Advance the cursor; throws IO_ERROR when aCount exceeds the remaining bytes.
std::string ReadLzt()
– strings ----------------------------------------------------------------—
void ExpectByte(uint8_t aValue, const wxString &aWhat)
Consume one byte and require the given value.
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
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_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,...)
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_PLACED_INSTANCE
@ ORCAD_ST_GRAPHIC_ARC_INST
@ ORCAD_ST_DRAWN_INSTANCE
hierarchical block instance
@ ORCAD_ST_GLOBAL
placed power symbol
@ ORCAD_ST_GRAPHIC_BITMAP_INST
@ ORCAD_ST_OFFPAGE_CONNECTOR
@ 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_SYMBOL_DISPLAY_PROP
@ ORCAD_ST_T0X11
bus pin instance (absolute pos)
@ 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.
int rotation
0..3 quarter turns
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
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.
bool isBus
true for structure type 21
std::vector< ORCAD_ALIAS > aliases
wxString result
Test unit parsing edge cases and error handling.