KiCad PCB EDA Suite
Loading...
Searching...
No Matches
orcad_stream.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 <cstring>
26
27#include <ki_exception.h>
28#include <wx/strconv.h>
29
30
31static wxString hexOf( const uint8_t* aBytes, size_t aCount )
32{
33 wxString out;
34
35 for( size_t i = 0; i < aCount; i++ )
36 out += wxString::Format( wxS( "%02x" ), aBytes[i] );
37
38 return out;
39}
40
41
42ORCAD_STREAM::ORCAD_STREAM( const void* aData, size_t aLength ) :
43 m_data( static_cast<const uint8_t*>( aData ) ),
44 m_size( aLength ),
45 m_offset( 0 )
46{
47}
48
49
50ORCAD_STREAM::ORCAD_STREAM( const std::vector<char>& aData ) :
51 ORCAD_STREAM( aData.data(), aData.size() )
52{
53}
54
55
56void ORCAD_STREAM::requireBytes( size_t aCount ) const
57{
58 if( m_offset > m_size || aCount > m_size - m_offset )
59 {
60 THROW_IO_ERRORF( wxS( "OrCAD stream: read of %zu bytes past end at 0x%zx (stream size 0x%zx)" ),
61 aCount,
63 m_size );
64 }
65}
66
67
69{
70 requireBytes( 1 );
71 return m_data[m_offset++];
72}
73
74
76{
77 return static_cast<int8_t>( ReadU8() );
78}
79
80
82{
83 requireBytes( 2 );
84 uint16_t v = static_cast<uint16_t>( m_data[m_offset] )
85 | static_cast<uint16_t>( m_data[m_offset + 1] ) << 8;
86 m_offset += 2;
87 return v;
88}
89
90
92{
93 return static_cast<int16_t>( ReadU16() );
94}
95
96
98{
99 requireBytes( 4 );
100 uint32_t v = static_cast<uint32_t>( m_data[m_offset] )
101 | static_cast<uint32_t>( m_data[m_offset + 1] ) << 8
102 | static_cast<uint32_t>( m_data[m_offset + 2] ) << 16
103 | static_cast<uint32_t>( m_data[m_offset + 3] ) << 24;
104 m_offset += 4;
105 return v;
106}
107
108
110{
111 return static_cast<int32_t>( ReadU32() );
112}
113
114
116{
117 size_t lenPos = m_offset;
118 uint16_t len = ReadU16();
119
120 if( m_offset > m_size || static_cast<size_t>( len ) + 1 > m_size - m_offset )
121 THROW_IO_ERRORF( wxS( "OrCAD stream: string of length %u at 0x%zx exceeds stream" ), len, lenPos );
122
123 std::string s( reinterpret_cast<const char*>( m_data + m_offset ), len );
124 m_offset += len;
125
126 if( m_data[m_offset] != 0 )
127 THROW_IO_ERRORF( wxS( "OrCAD stream: string at 0x%zx missing NUL terminator" ), lenPos );
128
129 m_offset++;
130 return s;
131}
132
133
135{
136 if( m_offset >= m_size )
137 THROW_IO_ERRORF( wxS( "OrCAD stream: read past end at 0x%zx" ), m_offset );
138
139 const void* nul = memchr( m_data + m_offset, 0, m_size - m_offset );
140
141 if( !nul )
142 THROW_IO_ERRORF( wxS( "OrCAD stream: unterminated string at 0x%zx" ), m_offset );
143
144 size_t end = static_cast<const uint8_t*>( nul ) - m_data;
145 std::string s( reinterpret_cast<const char*>( m_data + m_offset ), end - m_offset );
146 m_offset = end + 1;
147 return s;
148}
149
150
151std::vector<uint8_t> ORCAD_STREAM::ReadBytes( size_t aCount )
152{
153 requireBytes( aCount );
154 std::vector<uint8_t> v( m_data + m_offset, m_data + m_offset + aCount );
155 m_offset += aCount;
156 return v;
157}
158
159
160void ORCAD_STREAM::Skip( size_t aCount )
161{
162 if( m_offset > m_size || aCount > m_size - m_offset )
163 {
164 THROW_IO_ERRORF( wxS( "OrCAD stream: skip of %zu bytes past end at 0x%zx (stream size 0x%zx)" ),
165 aCount,
166 m_offset,
167 m_size );
168 }
169
170 m_offset += aCount;
171}
172
173
174int ORCAD_STREAM::PeekU8( size_t aAhead ) const
175{
176 size_t pos = m_offset + aAhead;
177
178 if( pos >= m_size )
179 return -1;
180
181 return m_data[pos];
182}
183
184
185bool ORCAD_STREAM::PeekMatches( const uint8_t* aBytes, size_t aCount, size_t aAhead ) const
186{
187 size_t pos = m_offset + aAhead;
188
189 if( pos > m_size || aCount > m_size - pos )
190 return false;
191
192 return memcmp( m_data + pos, aBytes, aCount ) == 0;
193}
194
195
196bool ORCAD_STREAM::AtPreamble( size_t aAhead ) const
197{
198 return PeekMatches( PREAMBLE, 4, aAhead );
199}
200
201
202bool ORCAD_STREAM::HasPreambleAt( size_t aAbsoluteOffset ) const
203{
204 if( aAbsoluteOffset > m_size || 4 > m_size - aAbsoluteOffset )
205 return false;
206
207 return memcmp( m_data + aAbsoluteOffset, PREAMBLE, 4 ) == 0;
208}
209
210
211size_t ORCAD_STREAM::FindPreamble( size_t aFrom ) const
212{
213 if( m_size < 4 )
214 return npos;
215
216 for( size_t pos = aFrom; pos + 4 <= m_size; pos++ )
217 {
218 if( m_data[pos] == PREAMBLE[0] && memcmp( m_data + pos, PREAMBLE, 4 ) == 0 )
219 return pos;
220 }
221
222 return npos;
223}
224
225
226void ORCAD_STREAM::Expect( const uint8_t* aBytes, size_t aCount, const wxString& aWhat )
227{
228 size_t pos = m_offset;
229 std::vector<uint8_t> got = ReadBytes( aCount );
230
231 if( memcmp( got.data(), aBytes, aCount ) != 0 )
232 {
233 THROW_IO_ERRORF( wxS( "OrCAD stream: expected %s got %s at 0x%zx (%s)" ),
234 hexOf( aBytes, aCount ),
235 hexOf( got.data(), aCount ),
236 pos,
237 aWhat );
238 }
239}
240
241
242void ORCAD_STREAM::ExpectByte( uint8_t aValue, const wxString& aWhat )
243{
244 Expect( &aValue, 1, aWhat );
245}
246
247
248void ORCAD_STREAM::ExpectPreamble( const wxString& aWhat )
249{
250 Expect( PREAMBLE, 4, aWhat );
251}
252
253
255{
256 if( AtPreamble() )
257 {
258 Skip( 4 );
259 uint32_t trail = ReadU32();
260 Skip( trail );
261 }
262}
263
264
265wxString FromOrcadString( const std::string& aText )
266{
267 if( aText.empty() )
268 return wxEmptyString;
269
270 wxString converted( aText.c_str(), wxCSConv( wxFONTENCODING_CP1252 ) );
271
272 if( converted.IsEmpty() )
273 converted = wxString::From8BitData( aText.c_str(), aText.size() );
274
275 // OrCAD multi-line text uses CR LF; raw CR renders as replacement glyph in KiCad.
276 converted.Replace( wxS( "\r\n" ), wxS( "\n" ) );
277 converted.Replace( wxS( "\r" ), wxS( "\n" ) );
278
279 return converted;
280}
void ExpectPreamble(const wxString &aWhat)
Consume the 4 preamble bytes; throws IO_ERROR naming aWhat when absent.
const uint8_t * m_data
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;...
bool AtPreamble(size_t aAhead=0) const
True when the 4 preamble bytes FF E4 5C 39 sit at cursor + aAhead.
uint8_t ReadU8()
static constexpr size_t npos
Returned by FindPreamble() when no further preamble exists.
int8_t ReadI8()
bool HasPreambleAt(size_t aAbsoluteOffset) const
True when the preamble sits at the given absolute offset (false if out of range).
uint16_t ReadU16()
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.
static constexpr uint8_t PREAMBLE[4]
Magic preceding every framed structure body: FF E4 5C 39.
std::string ReadLzt()
Read a length-prefixed zero-terminated string: u16 length, length content bytes, then a mandatory 0x0...
ORCAD_STREAM(const void *aData, size_t aLength)
void requireBytes(size_t aCount) const
Throw IO_ERROR unless aCount bytes remain at the cursor.
std::string ReadZt()
Read a bare zero-terminated string (no length prefix); consumes the NUL.
bool PeekMatches(const uint8_t *aBytes, size_t aCount, size_t aAhead=0) const
Compare aCount bytes at cursor + aAhead against aBytes without advancing.
int32_t ReadI32()
void ExpectByte(uint8_t aValue, const wxString &aWhat)
Consume one byte and require the given value.
uint32_t ReadU32()
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...
int16_t ReadI16()
#define THROW_IO_ERRORF(msg,...)
wxString FromOrcadString(const std::string &aText)
Decode raw stream bytes (Windows-1252) into a wxString for UI/UX use.
static wxString hexOf(const uint8_t *aBytes, size_t aCount)
VECTOR2I end