KiCad PCB EDA Suite
ALTIUM_PARSER Class Reference

#include <altium_parser.h>

Public Member Functions

 ALTIUM_PARSER (const CFB::CompoundFileReader &aReader, const CFB::COMPOUND_FILE_ENTRY *aEntry)
 
 ALTIUM_PARSER (std::unique_ptr< char[]> &aContent, size_t aSize)
 
 ~ALTIUM_PARSER ()=default
 
template<typename Type >
Type Read ()
 
wxString ReadWxString ()
 
std::vector< char > ReadVector (size_t aSize)
 
int32_t ReadKicadUnit ()
 
int32_t ReadKicadUnitX ()
 
int32_t ReadKicadUnitY ()
 
wxPoint ReadWxPoint ()
 
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 46 of file altium_parser.h.

Constructor & Destructor Documentation

◆ ALTIUM_PARSER() [1/2]

ALTIUM_PARSER::ALTIUM_PARSER ( const CFB::CompoundFileReader &  aReader,
const CFB::COMPOUND_FILE_ENTRY *  aEntry 
)

Definition at line 69 of file altium_parser.cpp.

71 {
72  m_subrecord_end = nullptr;
73  m_size = static_cast<size_t>( aEntry->size );
74  m_error = false;
75  m_content.reset( new char[m_size] );
76  m_pos = m_content.get();
77 
78  // read file into buffer
79  aReader.ReadFile( aEntry, 0, m_content.get(), m_size );
80 }
char * m_subrecord_end
std::unique_ptr< char[]> m_content

References 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 83 of file altium_parser.cpp.

84 {
85  m_subrecord_end = nullptr;
86  m_size = aSize;
87  m_error = false;
88  m_content = std::move( aContent );
89  m_pos = m_content.get();
90 }
char * m_subrecord_end
std::unique_ptr< char[]> m_content

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 177 of file altium_parser.cpp.

178 {
179  const double int_limit = ( std::numeric_limits<int>::max() - 1 ) / 2.54;
180 
181  int32_t iu = KiROUND( Clamp<double>( -int_limit, aValue, int_limit ) * 2.54 );
182 
183  // Altium stores metric units up to 0.001mm (1000nm) in accuracy. This code fixes rounding
184  // errors. Because imperial units > 0.01mil are always even, this workaround should never
185  // trigger for them.
186  switch( iu % 1000 )
187  {
188  case 1:
189  case -999:
190  return iu - 1;
191  case 999:
192  case -1:
193  return iu + 1;
194  default:
195  return iu;
196  }
197 }
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:73

References KiROUND().

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

◆ GetRemainingBytes()

◆ GetRemainingSubrecordBytes()

size_t ALTIUM_PARSER::GetRemainingSubrecordBytes ( ) const
inline

Definition at line 186 of file altium_parser.h.

187  {
188  return m_pos == nullptr || m_subrecord_end == nullptr || m_subrecord_end <= m_pos ?
189  0 :
191  };
char * m_subrecord_end

References m_pos, and m_subrecord_end.

Referenced by APAD6::APAD6().

◆ HasParsingError()

◆ Read()

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

Definition at line 54 of file altium_parser.h.

55  {
56  if( GetRemainingBytes() >= sizeof( Type ) )
57  {
58  Type val = *(Type*) ( m_pos );
59  m_pos += sizeof( Type );
60  return val;
61  }
62  else
63  {
64  m_error = true;
65  return 0;
66  }
67  }
size_t GetRemainingBytes() const

References GetRemainingBytes(), m_error, and m_pos.

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

◆ ReadAndSetSubrecordLength()

size_t ALTIUM_PARSER::ReadAndSetSubrecordLength ( )
inline

Definition at line 131 of file altium_parser.h.

132  {
133  uint32_t length = Read<uint32_t>();
134  m_subrecord_end = m_pos + length;
135  return length;
136  }
char * m_subrecord_end

References m_pos, and m_subrecord_end.

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

◆ ReadBool()

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

◆ ReadDouble()

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

Definition at line 208 of file altium_parser.cpp.

210 {
211  const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
212 
213  if( value == aProps.end() )
214  return aDefault;
215 
216  // Locale independent str -> double conversation
217  std::istringstream istr( (const char*) value->second.mb_str() );
218  istr.imbue( std::locale::classic() );
219 
220  double doubleValue;
221  istr >> doubleValue;
222  return doubleValue;
223 }

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

◆ ReadInt()

◆ 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 238 of file altium_parser.cpp.

240 {
241  const wxString& value = ReadString( aProps, aKey, aDefault );
242 
243  wxString prefix;
244 
245  if( !value.EndsWith( "mil", &prefix ) )
246  {
247  wxLogError( _( "Unit '%s' does not end with 'mil'." ), value );
248  return 0;
249  }
250 
251  double mils;
252 
253  if( !prefix.ToCDouble( &mils ) )
254  {
255  wxLogError( _( "Cannot convert '%s' to double." ), prefix );
256  return 0;
257  }
258 
259  return ConvertToKicadUnit( mils * 10000 );
260 }
#define _(s)
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
static int32_t ConvertToKicadUnit(const double aValue)

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

◆ ReadKicadUnitX()

int32_t ALTIUM_PARSER::ReadKicadUnitX ( )
inline

Definition at line 107 of file altium_parser.h.

108  {
109  return ReadKicadUnit();
110  }
int32_t ReadKicadUnit()

References ReadKicadUnit().

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

◆ ReadKicadUnitY()

int32_t ALTIUM_PARSER::ReadKicadUnitY ( )
inline

Definition at line 112 of file altium_parser.h.

113  {
114  return -ReadKicadUnit();
115  }
int32_t ReadKicadUnit()

References ReadKicadUnit().

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

◆ ReadProperties()

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

Definition at line 93 of file altium_parser.cpp.

94 {
95  std::map<wxString, wxString> kv;
96 
97  uint32_t length = Read<uint32_t>();
98 
99  if( length > GetRemainingBytes() )
100  {
101  m_error = true;
102  return kv;
103  }
104 
105  if( length == 0 )
106  {
107  return kv;
108  }
109 
110  // There is one case by kliment where Board6 ends with "|NEARDISTANCE=1000mi".
111  // Both the 'l' and the null-byte are missing, which looks like Altium swallowed two bytes.
112  bool hasNullByte = m_pos[length - 1] == '\0';
113 
114  if( !hasNullByte )
115  {
116  wxLogError( _( "Missing null byte at end of property list. Imported data might be "
117  "malformed or missing." ) );
118  }
119 
120  // we use std::string because std::string can handle NULL-bytes
121  // wxString would end the string at the first NULL-byte
122  std::string str = std::string( m_pos, length - ( hasNullByte ? 1 : 0 ) );
123  m_pos += length;
124 
125  std::size_t token_end = 0;
126 
127  while( token_end < str.size() && token_end != std::string::npos )
128  {
129  std::size_t token_start = str.find( '|', token_end );
130  std::size_t token_equal = str.find( '=', token_start );
131  token_end = str.find( '|', token_start + 1 );
132 
133  if( token_equal >= token_end )
134  {
135  continue; // this looks like an error: skip the entry. Also matches on std::string::npos
136  }
137 
138  if( token_end == std::string::npos )
139  {
140  token_end = str.size() + 1; // this is the correct offset
141  }
142 
143  std::string keyS = str.substr( token_start + 1, token_equal - token_start - 1 );
144  std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
145 
146  // convert the strings to wxStrings, since we use them everywhere
147  // value can have non-ASCII characters, so we convert them from LATIN1/ISO8859-1
148  wxString key( keyS.c_str(), wxConvISO8859_1 );
149  // Altium stores keys either in Upper, or in CamelCase. Lets unify it.
150  wxString canonicalKey = key.Trim( false ).Trim( true ).MakeUpper();
151  // If the key starts with '%UTF8%' we have to parse the value using UTF8
152  wxString value;
153 
154  if( canonicalKey.StartsWith( "%UTF8%" ) )
155  value = wxString( valueS.c_str(), wxConvUTF8 );
156  else
157  value = wxString( valueS.c_str(), wxConvISO8859_1 );
158 
159  // Breathless hack because I haven't a clue what the story is here (but this character
160  // appears in a lot of radial dimensions and is rendered by Altium as a space).
161  value.Replace( wxT( "ÿ" ), wxT( " " ) );
162 
163  if( canonicalKey == wxT( "DESIGNATOR" )
164  || canonicalKey == wxT( "NAME" )
165  || canonicalKey == wxT( "TEXT" ) )
166  {
167  value = AltiumPropertyToKiCadString( value.Trim() );
168  }
169 
170  kv.insert( { canonicalKey, value.Trim() } );
171  }
172 
173  return kv;
174 }
#define kv
size_t GetRemainingBytes() const
#define _(s)
wxString AltiumPropertyToKiCadString(const wxString &aString)

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

Referenced by ABOARD6::ABOARD6(), ACLASS6::ACLASS6(), ACOMPONENT6::ACOMPONENT6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), ADIMENSION6::ADIMENSION6(), AMODEL::AMODEL(), ANET6::ANET6(), APOLYGON6::APOLYGON6(), AREGION6::AREGION6(), ARULE6::ARULE6(), SCH_ALTIUM_PLUGIN::ParseFileHeader(), 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 87 of file altium_parser.h.

88  {
89  if( aSize > GetRemainingBytes() )
90  {
91  m_error = true;
92  return {};
93  }
94  else
95  {
96  std::vector<char> data( m_pos, m_pos + aSize );
97  m_pos += aSize;
98  return data;
99  }
100  }
size_t GetRemainingBytes() const

References GetRemainingBytes(), m_error, and m_pos.

Referenced by ASCH_STORAGE_FILE::ASCH_STORAGE_FILE().

◆ ReadWxPoint()

wxPoint ALTIUM_PARSER::ReadWxPoint ( )
inline

Definition at line 117 of file altium_parser.h.

118  {
119  int32_t x = ReadKicadUnitX();
120  int32_t y = ReadKicadUnitY();
121  return { x, y };
122  }
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().

◆ ReadWxSize()

wxSize ALTIUM_PARSER::ReadWxSize ( )
inline

Definition at line 124 of file altium_parser.h.

125  {
126  int32_t x = ReadKicadUnit();
127  int32_t y = ReadKicadUnit();
128  return { x, y };
129  }
int32_t ReadKicadUnit()

References ReadKicadUnit().

Referenced by APAD6::APAD6().

◆ ReadWxString()

wxString ALTIUM_PARSER::ReadWxString ( )
inline

Definition at line 69 of file altium_parser.h.

70  {
71  uint8_t len = Read<uint8_t>();
72  if( GetRemainingBytes() >= len )
73  {
74 
75  //altium uses LATIN1/ISO 8859-1, convert it
76  wxString val = wxString( m_pos, wxConvISO8859_1, len );
77  m_pos += len;
78  return val;
79  }
80  else
81  {
82  m_error = true;
83  return wxString( "" );
84  }
85  }
size_t GetRemainingBytes() const

References GetRemainingBytes(), m_error, and m_pos.

Referenced by APAD6::APAD6(), ASCH_STORAGE_FILE::ASCH_STORAGE_FILE(), ATEXT6::ATEXT6(), and ALTIUM_PCB::ParseFileHeader().

◆ Skip()

void ALTIUM_PARSER::Skip ( size_t  aLength)
inline

Definition at line 157 of file altium_parser.h.

158  {
159  if( GetRemainingBytes() >= aLength )
160  {
161  m_pos += aLength;
162  }
163  else
164  {
165  m_error = true;
166  }
167  }
size_t GetRemainingBytes() const

References GetRemainingBytes(), m_error, and m_pos.

Referenced by AARC6::AARC6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), ADIMENSION6::ADIMENSION6(), AFILL6::AFILL6(), APAD6::APAD6(), AREGION6::AREGION6(), ARULE6::ARULE6(), ASCH_STORAGE_FILE::ASCH_STORAGE_FILE(), ATEXT6::ATEXT6(), ATRACK6::ATRACK6(), and AVIA6::AVIA6().

◆ SkipSubrecord()

void ALTIUM_PARSER::SkipSubrecord ( )
inline

Definition at line 169 of file altium_parser.h.

170  {
171  if( m_subrecord_end == nullptr || m_subrecord_end < m_pos )
172  {
173  m_error = true;
174  }
175  else
176  {
178  }
179  };
char * m_subrecord_end

References m_error, m_pos, and m_subrecord_end.

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

Member Data Documentation

◆ m_content

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

Definition at line 199 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 200 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: