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 PropertiesReadInt (const std::map< wxString, wxString > &aProperties, const wxString &aKey, int aDefault)
 
static double PropertiesReadDouble (const std::map< wxString, wxString > &aProperties, const wxString &aKey, double aDefault)
 
static bool PropertiesReadBool (const std::map< wxString, wxString > &aProperties, const wxString &aKey, bool aDefault)
 
static int32_t PropertiesReadKicadUnit (const std::map< wxString, wxString > &aProperties, const wxString &aKey, const wxString &aDefault)
 
static wxString PropertiesReadString (const std::map< wxString, wxString > &aProperties, 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 47 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 66 of file altium_parser.cpp.

68 {
69  m_subrecord_end = nullptr;
70  m_size = static_cast<size_t>( aEntry->size );
71  m_error = false;
72  m_content.reset( new char[m_size] );
73  m_pos = m_content.get();
74 
75  // read file into buffer
76  aReader.ReadFile( aEntry, 0, m_content.get(), m_size );
77 }
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 80 of file altium_parser.cpp.

81 {
82  m_subrecord_end = nullptr;
83  m_size = aSize;
84  m_error = false;
85  m_content = std::move( aContent );
86  m_pos = m_content.get();
87 }
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()

static int32_t ALTIUM_PARSER::ConvertToKicadUnit ( const double  aValue)
inlinestatic

Definition at line 141 of file altium_parser.h.

142  {
143  const double int_limit = ( std::numeric_limits<int>::max() - 1 ) / 2.54;
144 
145  int32_t iu = KiROUND( Clamp<double>( -int_limit, aValue, int_limit ) * 2.54 );
146 
147  // Altium stores metric units up to 0.001mm (1000nm) in accuracy. This code fixes rounding errors.
148  // Because imperial units > 0.01mil are always even, this workaround should never trigger for them.
149  switch( iu % 1000 )
150  {
151  case 1:
152  case -999:
153  return iu - 1;
154  case 999:
155  case -1:
156  return iu + 1;
157  default:
158  return iu;
159  }
160  }
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:68

References KiROUND().

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

◆ GetRemainingBytes()

◆ GetRemainingSubrecordBytes()

size_t ALTIUM_PARSER::GetRemainingSubrecordBytes ( ) const
inline

Definition at line 206 of file altium_parser.h.

207  {
208  return m_pos == nullptr || m_subrecord_end == nullptr || m_subrecord_end <= m_pos ?
209  0 :
211  };
char * m_subrecord_end

References m_pos, and m_subrecord_end.

Referenced by APAD6::APAD6().

◆ HasParsingError()

◆ PropertiesReadBool()

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

◆ PropertiesReadDouble()

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

Definition at line 159 of file altium_parser.cpp.

161 {
162  const std::map<wxString, wxString>::const_iterator& value = aProperties.find( aKey );
163  if( value == aProperties.end() )
164  {
165  return aDefault;
166  }
167 
168  // Locale independent str -> double conversation
169  std::istringstream istr( (const char*) value->second.mb_str() );
170  istr.imbue( std::locale::classic() );
171 
172  double doubleValue;
173  istr >> doubleValue;
174  return doubleValue;
175 }

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

◆ PropertiesReadInt()

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

◆ PropertiesReadKicadUnit()

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

Definition at line 187 of file altium_parser.cpp.

189 {
190  const wxString& value = PropertiesReadString( aProperties, aKey, aDefault );
191 
192  wxString prefix;
193  if( !value.EndsWith( "mil", &prefix ) )
194  {
195  wxLogError( wxString::Format( "Unit '%s' does not end with mil", value ) );
196  return 0;
197  }
198 
199  double mils;
200  if( !prefix.ToCDouble( &mils ) )
201  {
202  wxLogError( wxString::Format( "Cannot convert '%s' into double", prefix ) );
203  return 0;
204  }
205 
206  return ConvertToKicadUnit( mils * 10000 );
207 }
static int32_t ConvertToKicadUnit(const double aValue)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
static wxString PropertiesReadString(const std::map< wxString, wxString > &aProperties, const wxString &aKey, const wxString &aDefault)

References ConvertToKicadUnit(), Format(), and PropertiesReadString().

Referenced by ABOARD6::ABOARD6(), ACOMPONENT6::ACOMPONENT6(), ACOMPONENTBODY6::ACOMPONENTBODY6(), ADIMENSION6::ADIMENSION6(), altium_parse_polygons(), APOLYGON6::APOLYGON6(), ARULE6::ARULE6(), and BOOST_AUTO_TEST_CASE().

◆ PropertiesReadString()

◆ Read()

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

Definition at line 55 of file altium_parser.h.

56  {
57  if( GetRemainingBytes() >= sizeof( Type ) )
58  {
59  Type val = *(Type*) ( m_pos );
60  m_pos += sizeof( Type );
61  return val;
62  }
63  else
64  {
65  m_error = true;
66  return 0;
67  }
68  }
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(), and AVIA6::AVIA6().

◆ ReadAndSetSubrecordLength()

size_t ALTIUM_PARSER::ReadAndSetSubrecordLength ( )
inline

Definition at line 132 of file altium_parser.h.

133  {
134  uint32_t length = Read<uint32_t>();
135  m_subrecord_end = m_pos + length;
136  return length;
137  }
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().

◆ ReadKicadUnit()

int32_t ALTIUM_PARSER::ReadKicadUnit ( )
inline

Definition at line 103 of file altium_parser.h.

104  {
105  return ConvertToKicadUnit( Read<int32_t>() );
106  }
static int32_t ConvertToKicadUnit(const double aValue)

References ConvertToKicadUnit().

Referenced by AARC6::AARC6(), APAD6::APAD6(), AREGION6::AREGION6(), ATEXT6::ATEXT6(), ATRACK6::ATRACK6(), AVIA6::AVIA6(), ReadKicadUnitX(), ReadKicadUnitY(), and ReadWxSize().

◆ ReadKicadUnitX()

int32_t ALTIUM_PARSER::ReadKicadUnitX ( )
inline

Definition at line 108 of file altium_parser.h.

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

References ReadKicadUnit().

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

◆ ReadKicadUnitY()

int32_t ALTIUM_PARSER::ReadKicadUnitY ( )
inline

Definition at line 113 of file altium_parser.h.

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

References ReadKicadUnit().

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

◆ ReadProperties()

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

Definition at line 90 of file altium_parser.cpp.

91 {
92  std::map<wxString, wxString> kv;
93 
94  uint32_t length = Read<uint32_t>();
95  if( length > GetRemainingBytes() )
96  {
97  m_error = true;
98  return kv;
99  }
100 
101  if( length == 0 )
102  {
103  return kv;
104  }
105 
106  // There is one case by kliment where Board6 ends with "|NEARDISTANCE=1000mi".
107  // Both the 'l' and the null-byte are missing, which looks like Altium swallowed two bytes.
108  bool hasNullByte = m_pos[length - 1] == '\0';
109  if( !hasNullByte )
110  {
111  wxLogError( "For Altium import, we assumes a null byte at the end of a list of properties. "
112  "Because this is missing, imported data might be malformed or missing." );
113  }
114 
115  // we use std::string because std::string can handle NULL-bytes
116  // wxString would end the string at the first NULL-byte
117  std::string str = std::string( m_pos, length - ( hasNullByte ? 1 : 0 ) );
118  m_pos += length;
119 
120  std::size_t token_end = 0;
121  while( token_end < str.size() && token_end != std::string::npos )
122  {
123  std::size_t token_start = str.find( '|', token_end );
124  std::size_t token_equal = str.find( '=', token_start );
125  token_end = str.find( '|', token_start + 1 );
126 
127  if( token_equal >= token_end )
128  {
129  continue; // this looks like an error: skip the entry. Also matches on std::string::npos
130  }
131 
132  if( token_end == std::string::npos )
133  {
134  token_end = str.size() + 1; // this is the correct offset
135  }
136 
137  std::string keyS = str.substr( token_start + 1, token_equal - token_start - 1 );
138  std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
139 
140  // convert the strings to wxStrings, since we use them everywhere
141  // value can have non-ASCII characters, so we convert them from LATIN1/ISO8859-1
142  wxString key( keyS.c_str(), wxConvISO8859_1 );
143  wxString value( valueS.c_str(), wxConvISO8859_1 );
144 
145  // Altium stores keys either in Upper, or in CamelCase. Lets unify it.
146  kv.insert( { key.Trim( false ).Trim( true ).MakeUpper(), value.Trim() } );
147  }
148 
149  return kv;
150 }
#define kv
size_t GetRemainingBytes() const

References 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().

◆ ReadVector()

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

Definition at line 88 of file altium_parser.h.

89  {
90  if( aSize > GetRemainingBytes() )
91  {
92  m_error = true;
93  return {};
94  }
95  else
96  {
97  std::vector<char> data( m_pos, m_pos + aSize );
98  m_pos += aSize;
99  return data;
100  }
101  }
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 118 of file altium_parser.h.

119  {
120  int32_t x = ReadKicadUnitX();
121  int32_t y = ReadKicadUnitY();
122  return { x, y };
123  }
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 125 of file altium_parser.h.

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

References ReadKicadUnit().

Referenced by APAD6::APAD6().

◆ ReadWxString()

wxString ALTIUM_PARSER::ReadWxString ( )
inline

Definition at line 70 of file altium_parser.h.

71  {
72  uint8_t len = Read<uint8_t>();
73  if( GetRemainingBytes() >= len )
74  {
75 
76  //altium uses LATIN1/ISO 8859-1, convert it
77  wxString val = wxString( m_pos, wxConvISO8859_1, len );
78  m_pos += len;
79  return val;
80  }
81  else
82  {
83  m_error = true;
84  return wxString( "" );
85  }
86  }
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 177 of file altium_parser.h.

178  {
179  if( GetRemainingBytes() >= aLength )
180  {
181  m_pos += aLength;
182  }
183  else
184  {
185  m_error = true;
186  }
187  }
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 189 of file altium_parser.h.

190  {
191  if( m_subrecord_end == nullptr || m_subrecord_end < m_pos )
192  {
193  m_error = true;
194  }
195  else
196  {
198  }
199  };
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 219 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 220 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: