KiCad PCB EDA Suite
Loading...
Searching...
No Matches
orcad_library.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 <cstdint>
26#include <utility>
27
28#include <ki_exception.h>
29
30
32{
33 ORCAD_PAGE_SETTINGS settings;
34
35 settings.createTimestamp = aStream.ReadU32();
36 settings.modifyTimestamp = aStream.ReadU32();
37 aStream.Skip( 16 ); // unknown
38
39 settings.width = aStream.ReadU32();
40 settings.height = aStream.ReadU32();
41 settings.pinToPin = aStream.ReadU32();
42
43 aStream.Skip( 2 );
44 settings.horizontalCount = aStream.ReadU16();
45 settings.verticalCount = aStream.ReadU16();
46 aStream.Skip( 2 );
47 settings.horizontalWidth = aStream.ReadU32();
48 settings.verticalWidth = aStream.ReadU32();
49 aStream.Skip( 48 ); // unknown
50 settings.horizontalChar = aStream.ReadU32() != 0;
51 aStream.Skip( 4 );
52 settings.horizontalAscending = aStream.ReadU32() != 0;
53 settings.verticalChar = aStream.ReadU32() != 0;
54 aStream.Skip( 4 );
55 settings.verticalAscending = aStream.ReadU32() != 0;
56
57 // 8 x u32 flags; flags[0] set = metric units (width/height in um, not mils)
58 uint32_t flags[8];
59
60 for( uint32_t& flag : flags )
61 flag = aStream.ReadU32();
62
63 settings.isMetric = flags[0] != 0;
64 settings.borderDisplayed = flags[1] != 0;
65 settings.borderPrinted = flags[2] != 0;
66 settings.gridRefDisplayed = flags[3] != 0;
67 settings.gridRefPrinted = flags[4] != 0;
68 settings.titleblockDisplayed = flags[5] != 0;
69 settings.titleblockPrinted = flags[6] != 0;
70 settings.ansiGridRefs = flags[7] != 0;
71
72 return settings;
73}
74
75
76ORCAD_LIBRARY_INFO OrcadParseLibrary( const std::vector<char>& aData )
77{
78 ORCAD_STREAM stream( aData );
80
81 // Introduction NUL-terminated in fixed 32-byte buffer; version words at offset 32
82 lib.introduction = stream.ReadZt();
83 stream.Seek( 32 );
84
85 lib.versionMajor = stream.ReadU16();
86 lib.versionMinor = stream.ReadU16();
87 lib.createTimestamp = stream.ReadU32();
88 lib.modifyTimestamp = stream.ReadU32();
89 stream.Skip( 4 ); // zeros
90
91 // u16 font count stores count+1; count-1 LOGFONTA records follow
92 int fontCount = stream.ReadU16();
93
94 for( int i = 0; i < fontCount - 1; i++ )
95 {
96 // 60-byte LOGFONTA; numeric fields through lfWeight, flags, then lfFaceName char[32].
97 ORCAD_FONT font;
98 font.height = stream.ReadI32();
99 font.width = stream.ReadI32();
100 font.escapement = stream.ReadI32();
101 font.orientation = stream.ReadI32();
102 font.bold = stream.ReadI32() >= 600;
103 font.italic = stream.ReadU8() != 0;
104 stream.Skip( 6 ); // underline, strikeout, charset and precision bytes
105 font.pitchAndFamily = stream.ReadU8();
106
107 std::vector<uint8_t> face = stream.ReadBytes( 32 );
108 size_t faceLen = 0;
109
110 while( faceLen < face.size() && face[faceLen] != 0 )
111 faceLen++;
112
113 font.face.assign( reinterpret_cast<const char*>( face.data() ), faceLen );
114
115 lib.fonts.push_back( std::move( font ) );
116 }
117
118 // Design Template font indices, then reserved slots and flags; v1.x has 17 slots and no count
119 uint16_t templateFontCount = lib.versionMajor >= 2 ? stream.ReadU16() : 17;
120 lib.templateFonts.resize( templateFontCount );
121
122 for( uint16_t i = 0; i < templateFontCount; ++i )
123 {
124 int fontIdx = stream.ReadU16();
125 lib.templateFonts[i] = fontIdx;
126
127 if( i == 10 && fontIdx > 0 )
128 lib.pinNameFont = i;
129 else if( i == 11 && fontIdx > 0 )
130 lib.pinNumberFont = i;
131 }
132
133 stream.Skip( 8 );
134
135 // 8 named part fields (Part Reference, Value, ...)
136 for( int i = 0; i < 8; i++ )
137 lib.partFields.push_back( stream.ReadLzt() );
138
139 ORCAD_PAGE_SETTINGS settings = OrcadParsePageSettings( stream );
140 lib.pinToPin = settings.pinToPin;
141
142 // The count width belongs to the format version: pre-2003 files store u16, later ones u32.
143 uint32_t stringCount = lib.versionMajor < 3 ? stream.ReadU16() : stream.ReadU32();
144
145 if( stringCount > 2000000
146 || static_cast<uint64_t>( stringCount ) * 3 > static_cast<uint64_t>( stream.Remaining() ) + 16 )
147 {
148 THROW_IO_ERRORF( wxS( "OrCAD library: string table count %u does not fit the stream" ), stringCount );
149 }
150
151 lib.strings.reserve( stringCount );
152
153 for( uint32_t i = 0; i < stringCount; i++ )
154 lib.strings.push_back( stream.ReadLzt() );
155
156 // Alias pairs and root schematic folder follow; both optional, so read failure
157 // must not sink whole library
158 try
159 {
160 uint16_t aliasCount = stream.ReadU16();
161
162 if( static_cast<uint64_t>( aliasCount ) * 2 <= stream.Remaining() + 4 )
163 {
164 for( uint16_t i = 0; i < aliasCount; i++ )
165 {
166 std::string alias = stream.ReadLzt();
167 std::string part = stream.ReadLzt();
168
169 lib.partAliases.emplace_back( std::move( alias ), std::move( part ) );
170 }
171 }
172
173 // Design files (not standalone libs) carry root schematic folder
174 if( lib.introduction.rfind( "OrCAD Windows Design", 0 ) == 0 )
175 {
176 stream.Skip( 8 );
177 lib.schematicName = stream.ReadLzt();
178 }
179 }
180 catch( const IO_ERROR& )
181 {
182 }
183
184 return lib;
185}
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
The caller owns the buffer.
size_t Remaining() const
Bytes left; 0 when the cursor is at or past the end.
uint8_t ReadU8()
– scalars (little-endian, bounds-checked, throw IO_ERROR on overrun) ----—
uint16_t ReadU16()
std::vector< uint8_t > ReadBytes(size_t aCount)
– buffers / cursor ---------------------------------------------------------—
void Skip(size_t aCount)
Advance the cursor; throws IO_ERROR when aCount exceeds the remaining bytes.
std::string ReadLzt()
– strings ----------------------------------------------------------------—
std::string ReadZt()
Consumes the NUL; throws IO_ERROR if no terminator remains.
void Seek(size_t aOffset)
Set the absolute cursor position; throws IO_ERROR when aOffset exceeds Size().
int32_t ReadI32()
uint32_t ReadU32()
#define THROW_IO_ERRORF(msg,...)
ORCAD_PAGE_SETTINGS OrcadParsePageSettings(ORCAD_STREAM &aStream)
Consumes 156 bytes; throws IO_ERROR on overrun.
ORCAD_LIBRARY_INFO OrcadParseLibrary(const std::vector< char > &aData)
The Library version selects the string-count width.
Font indices are one-based; zero selects the default.
uint8_t pitchAndFamily
bool bold
lfWeight >= 600
int orientation
glyph direction in tenths of a degree
int width
raw lfWidth; zero lets the font choose its natural aspect ratio
std::string face
int escapement
baseline direction in tenths of a degree
int height
raw lfHeight (typically negative)
std::string introduction
fixed 32-byte NUL-terminated buffer
std::vector< std::string > strings
global string table
std::vector< ORCAD_FONT > fonts
int pinNumberFont
Design Template font ID (slot 11)
std::vector< std::pair< std::string, std::string > > partAliases
std::vector< int > templateFonts
template font ID -> 1-based LOGFONT index
std::string schematicName
root schematic folder name
int pinNameFont
Design Template font ID (slot 10)
std::vector< std::string > partFields
the 8 named part fields
Dimensions use mils when isMetric is zero, otherwise micrometres.