KiCad PCB EDA Suite
altium_parser.h
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 (C) 2019-2020 Thomas Pointhuber <[email protected]>
5 * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#ifndef ALTIUM_PARSER_H
26#define ALTIUM_PARSER_H
27
28#include <map>
29#include <memory>
30#include <numeric>
31
32#include <wx/gdicmn.h>
33#include <math/vector2d.h>
34#include <vector>
35
36
37namespace CFB
38{
39class CompoundFileReader;
40struct COMPOUND_FILE_ENTRY;
41} // namespace CFB
42
48std::string FormatPath( const std::vector<std::string>& aVectorPath );
49
50
52{
53public:
59 ALTIUM_COMPOUND_FILE( const wxString& aFilePath );
60 ALTIUM_COMPOUND_FILE( const ALTIUM_COMPOUND_FILE& temp_obj ) = delete;
63
64 const CFB::CompoundFileReader& GetCompoundFileReader() const { return *m_reader; }
65
66 const CFB::COMPOUND_FILE_ENTRY* FindStream( const std::vector<std::string>& aStreamPath ) const;
67
68private:
69 std::unique_ptr<CFB::CompoundFileReader> m_reader;
70 std::vector<char> m_buffer;
71};
72
73
75{
76public:
77 ALTIUM_PARSER( const ALTIUM_COMPOUND_FILE& aFile, const CFB::COMPOUND_FILE_ENTRY* aEntry );
78 ALTIUM_PARSER( std::unique_ptr<char[]>& aContent, size_t aSize );
79 ~ALTIUM_PARSER() = default;
80
81 template <typename Type>
82 Type Read()
83 {
84 const size_t remainingBytes = GetRemainingBytes();
85 if( remainingBytes >= sizeof( Type ) )
86 {
87 Type val = *(Type*) ( m_pos );
88 m_pos += sizeof( Type );
89 return val;
90 }
91 else
92 {
93 m_pos += remainingBytes; // Ensure remaining bytes are zero
94 m_error = true;
95 return 0;
96 }
97 }
98
99 template <typename Type>
100 Type Peek()
101 {
102 char* const oldPos = m_pos;
103 const bool oldError = m_error;
104 Type result = Read<Type>();
105 m_pos = oldPos;
106 m_error = oldError;
107 return result;
108 }
109
110 wxString ReadWxString()
111 {
112 uint8_t len = Read<uint8_t>();
113 if( GetRemainingBytes() >= len )
114 {
115 // TODO: Identify where the actual code page is stored. For now, this default code page
116 // has limited impact, because recent Altium files come with a UTF16 string table
117 wxString val = wxString( m_pos, wxConvISO8859_1, len );
118 m_pos += len;
119 return val;
120 }
121 else
122 {
123 m_error = true;
124 return wxString( "" );
125 }
126 }
127
128 std::map<uint32_t, wxString> ReadWideStringTable()
129 {
130 std::map<uint32_t, wxString> table;
131 size_t remaining = GetRemainingBytes();
132
133 while( remaining >= 8 )
134 {
135 uint32_t index = Read<uint32_t>();
136 uint32_t length = Read<uint32_t>();
137 wxString str;
138 remaining -= 8;
139
140 if( length <= 2 )
141 length = 0; // for empty strings, not even the null bytes are present
142 else
143 {
144 if( length > remaining )
145 break;
146
147 str = wxString( m_pos, wxMBConvUTF16LE(), length - 2 );
148 }
149
150 table.emplace( index, str );
151 m_pos += length;
152 remaining -= length;
153 }
154
155 return table;
156 }
157
158 std::vector<char> ReadVector( size_t aSize )
159 {
160 if( aSize > GetRemainingBytes() )
161 {
162 m_error = true;
163 return {};
164 }
165 else
166 {
167 std::vector<char> data( m_pos, m_pos + aSize );
168 m_pos += aSize;
169 return data;
170 }
171 }
172
174 {
175 return ConvertToKicadUnit( Read<int32_t>() );
176 }
177
179 {
180 return ReadKicadUnit();
181 }
182
184 {
185 return -ReadKicadUnit();
186 }
187
189 {
190 int32_t x = ReadKicadUnitX();
191 int32_t y = ReadKicadUnitY();
192 return { x, y };
193 }
194
195 wxSize ReadWxSize()
196 {
197 int32_t x = ReadKicadUnit();
198 int32_t y = ReadKicadUnit();
199 return { x, y };
200 }
201
203 {
204 uint32_t length = Read<uint32_t>();
205 m_subrecord_end = m_pos + length;
206 return length;
207 }
208
209 std::map<wxString, wxString> ReadProperties();
210
211 static int32_t ConvertToKicadUnit( const double aValue );
212
213 static int ReadInt( const std::map<wxString, wxString>& aProps,
214 const wxString& aKey, int aDefault );
215
216 static double ReadDouble( const std::map<wxString, wxString>& aProps,
217 const wxString& aKey, double aDefault );
218
219 static bool ReadBool( const std::map<wxString, wxString>& aProps,
220 const wxString& aKey, bool aDefault );
221
222 static int32_t ReadKicadUnit( const std::map<wxString, wxString>& aProps,
223 const wxString& aKey, const wxString& aDefault );
224
225 static wxString ReadString( const std::map<wxString, wxString>& aProps,
226 const wxString& aKey, const wxString& aDefault );
227
228 void Skip( size_t aLength )
229 {
230 if( GetRemainingBytes() >= aLength )
231 {
232 m_pos += aLength;
233 }
234 else
235 {
236 m_error = true;
237 }
238 }
239
241 {
242 if( m_subrecord_end == nullptr || m_subrecord_end < m_pos )
243 {
244 m_error = true;
245 }
246 else
247 {
249 }
250 };
251
252 size_t GetRemainingBytes() const
253 {
254 return m_pos == nullptr ? 0 : m_size - ( m_pos - m_content.get() );
255 }
256
258 {
259 return m_pos == nullptr || m_subrecord_end == nullptr || m_subrecord_end <= m_pos ?
260 0 :
262 };
263
265 {
266 return m_error;
267 }
268
269private:
270 std::unique_ptr<char[]> m_content;
271 size_t m_size;
272
273 char* m_pos; // current read pointer
274 char* m_subrecord_end; // pointer which points to next subrecord start
276};
277
278
279#endif //ALTIUM_PARSER_H
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
const CFB::CompoundFileReader & GetCompoundFileReader() const
Definition: altium_parser.h:64
~ALTIUM_COMPOUND_FILE()=default
ALTIUM_COMPOUND_FILE & operator=(const ALTIUM_COMPOUND_FILE &temp_obj)=delete
std::vector< char > m_buffer
Definition: altium_parser.h:70
std::unique_ptr< CFB::CompoundFileReader > m_reader
Definition: altium_parser.h:69
ALTIUM_COMPOUND_FILE(const wxString &aFilePath)
Open a CFB file.
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
ALTIUM_COMPOUND_FILE(const ALTIUM_COMPOUND_FILE &temp_obj)=delete
wxString ReadWxString()
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
size_t GetRemainingBytes() const
int32_t ReadKicadUnitX()
bool HasParsingError()
std::map< wxString, wxString > ReadProperties()
size_t GetRemainingSubrecordBytes() const
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
std::map< uint32_t, wxString > ReadWideStringTable()
std::unique_ptr< char[]> m_content
~ALTIUM_PARSER()=default
size_t ReadAndSetSubrecordLength()
int32_t ReadKicadUnitY()
std::vector< char > ReadVector(size_t aSize)
static double ReadDouble(const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
static int32_t ConvertToKicadUnit(const double aValue)
int32_t ReadKicadUnit()
ALTIUM_PARSER(const ALTIUM_COMPOUND_FILE &aFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
wxSize ReadWxSize()
static bool ReadBool(const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
VECTOR2I ReadVector2I()
void Skip(size_t aLength)
char * m_subrecord_end
void SkipSubrecord()