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
31namespace
32{
33
34int32_t i32At( const std::vector<uint8_t>& aBytes, size_t aOffset )
35{
36 return static_cast<int32_t>( static_cast<uint32_t>( aBytes[aOffset] )
37 | static_cast<uint32_t>( aBytes[aOffset + 1] ) << 8
38 | static_cast<uint32_t>( aBytes[aOffset + 2] ) << 16
39 | static_cast<uint32_t>( aBytes[aOffset + 3] ) << 24 );
40}
41
42} // namespace
43
44
46{
47 ORCAD_PAGE_SETTINGS settings;
48
49 settings.createTimestamp = aStream.ReadU32();
50 settings.modifyTimestamp = aStream.ReadU32();
51 aStream.Skip( 16 ); // unknown
52
53 settings.width = aStream.ReadU32();
54 settings.height = aStream.ReadU32();
55 settings.pinToPin = aStream.ReadU32();
56
57 aStream.Skip( 2 );
58 settings.horizontalCount = aStream.ReadU16();
59 settings.verticalCount = aStream.ReadU16();
60 aStream.Skip( 2 );
61 settings.horizontalWidth = aStream.ReadU32();
62 settings.verticalWidth = aStream.ReadU32();
63 aStream.Skip( 48 ); // unknown
64 settings.horizontalChar = aStream.ReadU32() != 0;
65 aStream.Skip( 4 );
66 settings.horizontalAscending = aStream.ReadU32() != 0;
67 settings.verticalChar = aStream.ReadU32() != 0;
68 aStream.Skip( 4 );
69 settings.verticalAscending = aStream.ReadU32() != 0;
70
71 // 8 x u32 flags; flags[0] set = metric units (width/height in um, not mils)
72 uint32_t flags[8];
73
74 for( uint32_t& flag : flags )
75 flag = aStream.ReadU32();
76
77 settings.isMetric = flags[0] != 0;
78 settings.borderDisplayed = flags[1] != 0;
79 settings.borderPrinted = flags[2] != 0;
80 settings.gridRefDisplayed = flags[3] != 0;
81 settings.gridRefPrinted = flags[4] != 0;
82 settings.titleblockDisplayed = flags[5] != 0;
83 settings.titleblockPrinted = flags[6] != 0;
84 settings.ansiGridRefs = flags[7] != 0;
85
86 return settings;
87}
88
89
90ORCAD_LIBRARY_INFO OrcadParseLibrary( const std::vector<char>& aData )
91{
92 ORCAD_STREAM stream( aData );
94
95 // Introduction NUL-terminated in fixed 32-byte buffer; version words at offset 32
96 lib.introduction = stream.ReadZt();
97 stream.Seek( 32 );
98
99 lib.versionMajor = stream.ReadU16();
100 lib.versionMinor = stream.ReadU16();
101 lib.createTimestamp = stream.ReadU32();
102 lib.modifyTimestamp = stream.ReadU32();
103 stream.Skip( 4 ); // zeros
104
105 // u16 font count stores count+1; count-1 LOGFONTA records follow
106 int fontCount = stream.ReadU16();
107
108 for( int i = 0; i < fontCount - 1; i++ )
109 {
110 // 60-byte LOGFONTA; numeric fields through lfWeight, flags, then lfFaceName char[32].
111 std::vector<uint8_t> rec = stream.ReadBytes( 60 );
112
113 ORCAD_FONT font;
114 font.height = i32At( rec, 0 );
115 font.width = i32At( rec, 4 );
116 font.escapement = i32At( rec, 8 );
117 font.orientation = i32At( rec, 12 );
118 font.italic = rec[20] != 0;
119 font.bold = i32At( rec, 16 ) >= 600;
120 font.pitchAndFamily = rec[27];
121
122 size_t faceLen = 0;
123
124 while( faceLen < 32 && rec[28 + faceLen] != 0 )
125 faceLen++;
126
127 font.face.assign( reinterpret_cast<const char*>( rec.data() + 28 ), faceLen );
128
129 lib.fonts.push_back( std::move( font ) );
130 }
131
132 if( lib.versionMajor >= 2 )
133 {
134 // Design Template font indices followed by reserved slots and flags.
135 uint16_t someLen = stream.ReadU16();
136 lib.templateFonts.resize( someLen );
137
138 for( uint16_t i = 0; i < someLen; ++i )
139 {
140 int fontIdx = stream.ReadU16();
141 lib.templateFonts[i] = fontIdx;
142
143 if( i == 10 && fontIdx > 0 )
144 lib.pinNameFont = i;
145 else if( i == 11 && fontIdx > 0 )
146 lib.pinNumberFont = i;
147 }
148
149 stream.Skip( 8 );
150 }
151 else
152 {
153 // v1.x has the same first 17 slots without a count field.
154 lib.templateFonts.resize( 17 );
155
156 for( int i = 0; i < 17; ++i )
157 {
158 int fontIdx = stream.ReadU16();
159 lib.templateFonts[i] = fontIdx;
160
161 if( i == 10 && fontIdx > 0 )
162 lib.pinNameFont = i;
163 else if( i == 11 && fontIdx > 0 )
164 lib.pinNumberFont = i;
165 }
166
167 stream.Skip( 8 );
168 }
169
170 // 8 named part fields (Part Reference, Value, ...)
171 for( int i = 0; i < 8; i++ )
172 lib.partFields.push_back( stream.ReadLzt() );
173
174 ORCAD_PAGE_SETTINGS settings = OrcadParsePageSettings( stream );
175 lib.pinToPin = settings.pinToPin;
176
177 // The count width belongs to the format version: pre-2003 files store u16, later ones u32.
178 uint32_t stringCount = lib.versionMajor < 3 ? stream.ReadU16() : stream.ReadU32();
179
180 if( stringCount > 2000000
181 || static_cast<uint64_t>( stringCount ) * 3 > static_cast<uint64_t>( stream.Remaining() ) + 16 )
182 {
183 THROW_IO_ERRORF( wxS( "OrCAD library: string table count %u does not fit the stream" ), stringCount );
184 }
185
186 lib.strings.reserve( stringCount );
187
188 for( uint32_t i = 0; i < stringCount; i++ )
189 lib.strings.push_back( stream.ReadLzt() );
190
191 // Alias pairs and root schematic folder follow; both optional, so read failure
192 // must not sink whole library
193 try
194 {
195 uint16_t aliasCount = stream.ReadU16();
196
197 if( static_cast<uint64_t>( aliasCount ) * 2 <= stream.Remaining() + 4 )
198 {
199 for( uint16_t i = 0; i < aliasCount; i++ )
200 {
201 std::string alias = stream.ReadLzt();
202 std::string part = stream.ReadLzt();
203
204 lib.partAliases.emplace_back( std::move( alias ), std::move( part ) );
205 }
206 }
207
208 // Design files (not standalone libs) carry root schematic folder
209 if( lib.introduction.rfind( "OrCAD Windows Design", 0 ) == 0 )
210 {
211 stream.Skip( 8 );
212 lib.schematicName = stream.ReadLzt();
213 }
214 }
215 catch( const IO_ERROR& )
216 {
217 }
218
219 return lib;
220}
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.
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().
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.