KiCad PCB EDA Suite
ALTIUM_PARSER Class Reference

#include <altium_parser.h>

Public Member Functions

 ALTIUM_PARSER (const ALTIUM_COMPOUND_FILE &aFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
 
 ALTIUM_PARSER (std::unique_ptr< char[]> &aContent, size_t aSize)
 
 ~ALTIUM_PARSER ()=default
 
template<typename Type >
Type Read ()
 
template<typename Type >
Type Peek ()
 
wxString ReadWxString ()
 
std::map< uint32_t, wxString > ReadWideStringTable ()
 
std::vector< char > ReadVector (size_t aSize)
 
int32_t ReadKicadUnit ()
 
int32_t ReadKicadUnitX ()
 
int32_t ReadKicadUnitY ()
 
VECTOR2I ReadVector2I ()
 
wxSize ReadWxSize ()
 
size_t ReadAndSetSubrecordLength ()
 
std::map< wxString, wxString > ReadProperties ()
 
void Skip (size_t aLength)
 
void SkipSubrecord ()
 
size_t GetRemainingBytes () const
 
size_t GetRemainingSubrecordBytes () const
 
bool HasParsingError ()
 

Static Public Member Functions

static int32_t ConvertToKicadUnit (const double aValue)
 
static int ReadInt (const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
 
static double ReadDouble (const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
 
static bool ReadBool (const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
 
static int32_t ReadKicadUnit (const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
 
static wxString ReadString (const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
 

Private Attributes

std::unique_ptr< char[]> m_content
 
size_t m_size
 
char * m_pos
 
char * m_subrecord_end
 
bool m_error
 

Detailed Description

Definition at line 74 of file altium_parser.h.

Constructor & Destructor Documentation

◆ ALTIUM_PARSER() [1/2]

ALTIUM_PARSER::ALTIUM_PARSER ( const ALTIUM_COMPOUND_FILE aFile,
const CFB::COMPOUND_FILE_ENTRY *  aEntry 
)

Definition at line 145 of file altium_parser.cpp.

147{
148 m_subrecord_end = nullptr;
149 m_size = static_cast<size_t>( aEntry->size );
150 m_error = false;
151 m_content.reset( new char[m_size] );
152 m_pos = m_content.get();
153
154 // read file into buffer
155 aFile.GetCompoundFileReader().ReadFile( aEntry, 0, m_content.get(), m_size );
156}
const CFB::CompoundFileReader & GetCompoundFileReader() const
Definition: altium_parser.h:64
std::unique_ptr< char[]> m_content
char * m_subrecord_end

References ALTIUM_COMPOUND_FILE::GetCompoundFileReader(), m_content, m_error, m_pos, m_size, and m_subrecord_end.

◆ ALTIUM_PARSER() [2/2]

ALTIUM_PARSER::ALTIUM_PARSER ( std::unique_ptr< char[]> &  aContent,
size_t  aSize 
)

Definition at line 159 of file altium_parser.cpp.

160{
161 m_subrecord_end = nullptr;
162 m_size = aSize;
163 m_error = false;
164 m_content = std::move( aContent );
165 m_pos = m_content.get();
166}

References m_content, m_error, m_pos, m_size, and m_subrecord_end.

◆ ~ALTIUM_PARSER()

ALTIUM_PARSER::~ALTIUM_PARSER ( )
default

Member Function Documentation

◆ ConvertToKicadUnit()

int32_t ALTIUM_PARSER::ConvertToKicadUnit ( const double  aValue)
static

Definition at line 253 of file altium_parser.cpp.

254{
255 constexpr double int_limit = ( std::numeric_limits<int>::max() - 10 ) / 2.54;
256
257 int32_t iu = KiROUND( Clamp<double>( -int_limit, aValue, int_limit ) * 2.54 );
258
259 // Altium's internal precision is 0.1uinch. KiCad's is 1nm. Round to nearest 10nm to clean
260 // up most rounding errors. This allows lossless conversion of increments of 0.05mils and
261 // 0.01um.
262 return KiROUND( (double) iu / 10.0 ) * 10;
263}
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85

References KiROUND().

Referenced by AREGION6::AREGION6(), BOOST_AUTO_TEST_CASE(), and ReadKicadUnit().

◆ GetRemainingBytes()

◆ GetRemainingSubrecordBytes()

size_t ALTIUM_PARSER::GetRemainingSubrecordBytes ( ) const
inline

Definition at line 257 of file altium_parser.h.

258 {
259 return m_pos == nullptr || m_subrecord_end == nullptr || m_subrecord_end <= m_pos ?
260 0 :
262 };

References m_pos, and m_subrecord_end.

Referenced by AARC6::AARC6(), AFILL6::AFILL6(), APAD6::APAD6(), and ATRACK6::ATRACK6().

◆ HasParsingError()

◆ Peek()

template<typename Type >
Type ALTIUM_PARSER::Peek ( )
inline

Definition at line 100 of file altium_parser.h.

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 }

References m_error, and m_pos.

Referenced by ALTIUM_PCB::ParseFootprint().

◆ Read()

template<typename Type >
Type ALTIUM_PARSER::Read ( )
inline

Definition at line 82 of file altium_parser.h.

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 }
size_t GetRemainingBytes() const

References GetRemainingBytes(), m_error, and m_pos.

Referenced by AARC6::AARC6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), AFILL6::AFILL6(), APAD6::APAD6(), AREGION6::AREGION6(), ASCH_ADDITIONAL_FILE::ASCH_ADDITIONAL_FILE(), ASCH_STORAGE_FILE::ASCH_STORAGE_FILE(), ATEXT6::ATEXT6(), ATRACK6::ATRACK6(), AVIA6::AVIA6(), ALTIUM_DESIGNER_PLUGIN::FootprintEnumerate(), and ALTIUM_PCB::Parse().

◆ ReadAndSetSubrecordLength()

size_t ALTIUM_PARSER::ReadAndSetSubrecordLength ( )
inline

◆ ReadBool()

◆ ReadDouble()

double ALTIUM_PARSER::ReadDouble ( const std::map< wxString, wxString > &  aProps,
const wxString &  aKey,
double  aDefault 
)
static

Definition at line 274 of file altium_parser.cpp.

276{
277 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
278
279 if( value == aProps.end() )
280 return aDefault;
281
282 // Locale independent str -> double conversation
283 std::istringstream istr( (const char*) value->second.mb_str() );
284 istr.imbue( std::locale::classic() );
285
286 double doubleValue;
287 istr >> doubleValue;
288 return doubleValue;
289}

Referenced by ABOARD6::ABOARD6(), ACOMPONENT6::ACOMPONENT6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), ADIMENSION6::ADIMENSION6(), altium_parse_polygons(), AMODEL::AMODEL(), and ASCH_ARC::ASCH_ARC().

◆ ReadInt()

int ALTIUM_PARSER::ReadInt ( const std::map< wxString, wxString > &  aProps,
const wxString &  aKey,
int  aDefault 
)
static

Definition at line 266 of file altium_parser.cpp.

268{
269 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
270 return value == aProps.end() ? aDefault : wxAtoi( value->second );
271}

Referenced by ABOARD6::ABOARD6(), ACLASS6::ACLASS6(), ACOMPONENT6::ACOMPONENT6(), ADIMENSION6::ADIMENSION6(), AEXTENDED_PRIMITIVE_INFORMATION::AEXTENDED_PRIMITIVE_INFORMATION(), altium_parse_polygons(), APOLYGON6::APOLYGON6(), AREGION6::AREGION6(), ARULE6::ARULE6(), ASCH_ARC::ASCH_ARC(), ASCH_BEZIER::ASCH_BEZIER(), ASCH_BUS::ASCH_BUS(), ASCH_ELLIPSE::ASCH_ELLIPSE(), ASCH_HARNESS_CONNECTOR::ASCH_HARNESS_CONNECTOR(), ASCH_HARNESS_ENTRY::ASCH_HARNESS_ENTRY(), ASCH_HARNESS_TYPE::ASCH_HARNESS_TYPE(), ASCH_IMAGE::ASCH_IMAGE(), ASCH_IMPLEMENTATION::ASCH_IMPLEMENTATION(), ASCH_LABEL::ASCH_LABEL(), ASCH_LINE::ASCH_LINE(), ASCH_NO_ERC::ASCH_NO_ERC(), ASCH_PIN::ASCH_PIN(), ASCH_POLYGON::ASCH_POLYGON(), ASCH_POLYLINE::ASCH_POLYLINE(), ASCH_PORT::ASCH_PORT(), ASCH_RECTANGLE::ASCH_RECTANGLE(), ASCH_ROUND_RECTANGLE::ASCH_ROUND_RECTANGLE(), ASCH_SHEET::ASCH_SHEET(), ASCH_SHEET_FONT::ASCH_SHEET_FONT(), ASCH_SHEET_SYMBOL::ASCH_SHEET_SYMBOL(), ASCH_SIGNAL_HARNESS::ASCH_SIGNAL_HARNESS(), ASCH_SYMBOL::ASCH_SYMBOL(), ASCH_TEXT_FRAME::ASCH_TEXT_FRAME(), ASCH_WIRE::ASCH_WIRE(), SCH_ALTIUM_PLUGIN::ParseAdditional(), SCH_ALTIUM_PLUGIN::ParseFileHeader(), SCH_ALTIUM_PLUGIN::ParseStorage(), ReadEnum(), ReadKiCadUnitFrac(), ReadKiCadUnitFrac1(), ReadOwnerIndex(), ReadOwnerPartId(), and ReadRecord().

◆ ReadKicadUnit() [1/2]

◆ ReadKicadUnit() [2/2]

int32_t ALTIUM_PARSER::ReadKicadUnit ( const std::map< wxString, wxString > &  aProps,
const wxString &  aKey,
const wxString &  aDefault 
)
static

Definition at line 304 of file altium_parser.cpp.

306{
307 const wxString& value = ReadString( aProps, aKey, aDefault );
308
309 wxString prefix;
310
311 if( !value.EndsWith( "mil", &prefix ) )
312 {
313 wxLogError( _( "Unit '%s' does not end with 'mil'." ), value );
314 return 0;
315 }
316
317 double mils;
318
319 if( !prefix.ToCDouble( &mils ) )
320 {
321 wxLogError( _( "Cannot convert '%s' to double." ), prefix );
322 return 0;
323 }
324
325 return ConvertToKicadUnit( mils * 10000 );
326}
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
#define _(s)

References _, ConvertToKicadUnit(), and ReadString().

◆ ReadKicadUnitX()

int32_t ALTIUM_PARSER::ReadKicadUnitX ( )
inline

Definition at line 178 of file altium_parser.h.

179 {
180 return ReadKicadUnit();
181 }
int32_t ReadKicadUnit()

References ReadKicadUnit().

Referenced by APAD6::APAD6(), and ReadVector2I().

◆ ReadKicadUnitY()

int32_t ALTIUM_PARSER::ReadKicadUnitY ( )
inline

Definition at line 183 of file altium_parser.h.

184 {
185 return -ReadKicadUnit();
186 }

References ReadKicadUnit().

Referenced by APAD6::APAD6(), and ReadVector2I().

◆ ReadProperties()

std::map< wxString, wxString > ALTIUM_PARSER::ReadProperties ( )

Definition at line 169 of file altium_parser.cpp.

170{
171 std::map<wxString, wxString> kv;
172
173 uint32_t length = Read<uint32_t>();
174
175 if( length > GetRemainingBytes() )
176 {
177 m_error = true;
178 return kv;
179 }
180
181 if( length == 0 )
182 {
183 return kv;
184 }
185
186 // There is one case by kliment where Board6 ends with "|NEARDISTANCE=1000mi".
187 // Both the 'l' and the null-byte are missing, which looks like Altium swallowed two bytes.
188 bool hasNullByte = m_pos[length - 1] == '\0';
189
190 if( !hasNullByte )
191 {
192 wxLogError( _( "Missing null byte at end of property list. Imported data might be "
193 "malformed or missing." ) );
194 }
195
196 // we use std::string because std::string can handle NULL-bytes
197 // wxString would end the string at the first NULL-byte
198 std::string str = std::string( m_pos, length - ( hasNullByte ? 1 : 0 ) );
199 m_pos += length;
200
201 std::size_t token_end = 0;
202
203 while( token_end < str.size() && token_end != std::string::npos )
204 {
205 std::size_t token_start = str.find( '|', token_end );
206 std::size_t token_equal = str.find( '=', token_start );
207 token_end = str.find( '|', token_start + 1 );
208
209 if( token_equal >= token_end )
210 {
211 continue; // this looks like an error: skip the entry. Also matches on std::string::npos
212 }
213
214 if( token_end == std::string::npos )
215 {
216 token_end = str.size() + 1; // this is the correct offset
217 }
218
219 std::string keyS = str.substr( token_start + 1, token_equal - token_start - 1 );
220 std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
221
222 // convert the strings to wxStrings, since we use them everywhere
223 // value can have non-ASCII characters, so we convert them from LATIN1/ISO8859-1
224 wxString key( keyS.c_str(), wxConvISO8859_1 );
225 // Altium stores keys either in Upper, or in CamelCase. Lets unify it.
226 wxString canonicalKey = key.Trim( false ).Trim( true ).MakeUpper();
227 // If the key starts with '%UTF8%' we have to parse the value using UTF8
228 wxString value;
229
230 if( canonicalKey.StartsWith( "%UTF8%" ) )
231 value = wxString( valueS.c_str(), wxConvUTF8 );
232 else
233 value = wxString( valueS.c_str(), wxConvISO8859_1 );
234
235 // Breathless hack because I haven't a clue what the story is here (but this character
236 // appears in a lot of radial dimensions and is rendered by Altium as a space).
237 value.Replace( wxT( "ÿ" ), wxT( " " ) );
238
239 if( canonicalKey == wxT( "DESIGNATOR" )
240 || canonicalKey == wxT( "NAME" )
241 || canonicalKey == wxT( "TEXT" ) )
242 {
243 value = AltiumPropertyToKiCadString( value.Trim() );
244 }
245
246 kv.insert( { canonicalKey, value.Trim() } );
247 }
248
249 return kv;
250}
wxString AltiumPropertyToKiCadString(const wxString &aString)
#define kv

References _, AltiumPropertyToKiCadString(), GetRemainingBytes(), kv, m_error, and m_pos.

Referenced by ABOARD6::ABOARD6(), ACLASS6::ACLASS6(), ACOMPONENT6::ACOMPONENT6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), ADIMENSION6::ADIMENSION6(), AEXTENDED_PRIMITIVE_INFORMATION::AEXTENDED_PRIMITIVE_INFORMATION(), AMODEL::AMODEL(), ANET6::ANET6(), APOLYGON6::APOLYGON6(), AREGION6::AREGION6(), ARULE6::ARULE6(), BOOST_AUTO_TEST_CASE(), ALTIUM_DESIGNER_PLUGIN::FootprintEnumerate(), SCH_ALTIUM_PLUGIN::ParseAdditional(), SCH_ALTIUM_PLUGIN::ParseFileHeader(), ALTIUM_PCB::ParseFootprint(), and SCH_ALTIUM_PLUGIN::ParseStorage().

◆ ReadString()

wxString ALTIUM_PARSER::ReadString ( const std::map< wxString, wxString > &  aProps,
const wxString &  aKey,
const wxString &  aDefault 
)
static

◆ ReadVector()

std::vector< char > ALTIUM_PARSER::ReadVector ( size_t  aSize)
inline

Definition at line 158 of file altium_parser.h.

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 }

References GetRemainingBytes(), m_error, and m_pos.

Referenced by ASCH_ADDITIONAL_FILE::ASCH_ADDITIONAL_FILE(), and ASCH_STORAGE_FILE::ASCH_STORAGE_FILE().

◆ ReadVector2I()

VECTOR2I ALTIUM_PARSER::ReadVector2I ( )
inline

Definition at line 188 of file altium_parser.h.

189 {
190 int32_t x = ReadKicadUnitX();
191 int32_t y = ReadKicadUnitY();
192 return { x, y };
193 }
int32_t ReadKicadUnitX()
int32_t ReadKicadUnitY()

References ReadKicadUnitX(), and ReadKicadUnitY().

Referenced by AARC6::AARC6(), AFILL6::AFILL6(), APAD6::APAD6(), AREGION6::AREGION6(), ATEXT6::ATEXT6(), ATRACK6::ATRACK6(), and AVIA6::AVIA6().

◆ ReadWideStringTable()

std::map< uint32_t, wxString > ALTIUM_PARSER::ReadWideStringTable ( )
inline

Definition at line 128 of file altium_parser.h.

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 }

References GetRemainingBytes(), and m_pos.

Referenced by ALTIUM_PCB::ParseWideStrings6Data().

◆ ReadWxSize()

wxSize ALTIUM_PARSER::ReadWxSize ( )
inline

Definition at line 195 of file altium_parser.h.

196 {
197 int32_t x = ReadKicadUnit();
198 int32_t y = ReadKicadUnit();
199 return { x, y };
200 }

References ReadKicadUnit().

Referenced by APAD6::APAD6().

◆ ReadWxString()

wxString ALTIUM_PARSER::ReadWxString ( )
inline

Definition at line 110 of file altium_parser.h.

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 }

References GetRemainingBytes(), m_error, and m_pos.

Referenced by APAD6::APAD6(), ASCH_ADDITIONAL_FILE::ASCH_ADDITIONAL_FILE(), ASCH_STORAGE_FILE::ASCH_STORAGE_FILE(), ATEXT6::ATEXT6(), ALTIUM_DESIGNER_PLUGIN::FootprintEnumerate(), ALTIUM_PCB::ParseFileHeader(), and ALTIUM_PCB::ParseFootprint().

◆ Skip()

void ALTIUM_PARSER::Skip ( size_t  aLength)
inline

◆ SkipSubrecord()

void ALTIUM_PARSER::SkipSubrecord ( )
inline

Member Data Documentation

◆ m_content

std::unique_ptr<char[]> ALTIUM_PARSER::m_content
private

Definition at line 270 of file altium_parser.h.

Referenced by ALTIUM_PARSER(), and GetRemainingBytes().

◆ m_error

bool ALTIUM_PARSER::m_error
private

◆ m_pos

◆ m_size

size_t ALTIUM_PARSER::m_size
private

Definition at line 271 of file altium_parser.h.

Referenced by ALTIUM_PARSER(), and GetRemainingBytes().

◆ m_subrecord_end

char* ALTIUM_PARSER::m_subrecord_end
private

The documentation for this class was generated from the following files: