27#include <compoundfilereader.h>
34#include <wx/translation.h>
38std::string
FormatPath(
const std::vector<std::string>& aVectorPath )
40 return std::accumulate( aVectorPath.cbegin(), aVectorPath.cend(), std::string(),
41 [](
const std::string& ss,
const std::string& s )
43 return ss.empty() ? s : ss +
'\\' + s;
51 FILE* fp = wxFopen( aFilePath,
"rb" );
55 THROW_IO_ERROR( wxString::Format(
_(
"Cannot open file '%s'." ), aFilePath ) );
58 fseek( fp, 0, SEEK_END );
59 long len = ftell( fp );
70 fseek( fp, 0, SEEK_SET );
72 size_t bytesRead = fread(
m_buffer.data(),
sizeof(
unsigned char ), len, fp );
75 if(
static_cast<size_t>( len ) != bytesRead )
84 catch( CFB::CFBException& exception )
91static const CFB::COMPOUND_FILE_ENTRY*
93 const CFB::COMPOUND_FILE_ENTRY* aEntry,
const std::string aName,
94 const bool aIsStream )
96 const CFB::COMPOUND_FILE_ENTRY* ret =
nullptr;
98 aReader.EnumFiles( aEntry, 1,
99 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string& dir,
102 if( aReader.IsStream( entry ) == aIsStream )
104 std::string name = UTF16ToUTF8( entry->name );
105 if( name == aName.c_str() )
115const CFB::COMPOUND_FILE_ENTRY*
123 const CFB::COMPOUND_FILE_ENTRY* currentDirEntry =
m_reader->GetRootEntry();
125 auto it = aStreamPath.cbegin();
126 while( currentDirEntry !=
nullptr )
128 const std::string&
name = *it;
130 if( ++it == aStreamPath.cend() )
146 const CFB::COMPOUND_FILE_ENTRY* aEntry )
149 m_size =
static_cast<size_t>( aEntry->size );
171 std::map<wxString, wxString>
kv;
173 uint32_t length = Read<uint32_t>();
188 bool hasNullByte =
m_pos[length - 1] ==
'\0';
192 wxLogError(
_(
"Missing null byte at end of property list. Imported data might be "
193 "malformed or missing." ) );
198 std::string str = std::string(
m_pos, length - ( hasNullByte ? 1 : 0 ) );
201 std::size_t token_end = 0;
203 while( token_end < str.size() && token_end != std::string::npos )
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 );
209 if( token_equal >= token_end )
214 if( token_end == std::string::npos )
216 token_end = str.size() + 1;
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 );
224 wxString key( keyS.c_str(), wxConvISO8859_1 );
226 wxString canonicalKey = key.Trim(
false ).Trim(
true ).MakeUpper();
230 if( canonicalKey.StartsWith(
"%UTF8%" ) )
231 value = wxString( valueS.c_str(), wxConvUTF8 );
233 value = wxString( valueS.c_str(), wxConvISO8859_1 );
237 value.Replace( wxT(
"ÿ" ), wxT(
" " ) );
239 if( canonicalKey == wxT(
"DESIGNATOR" )
240 || canonicalKey == wxT(
"NAME" )
241 || canonicalKey == wxT(
"TEXT" ) )
246 kv.insert( { canonicalKey, value.Trim() } );
255 constexpr double int_limit = ( std::numeric_limits<int>::max() - 10 ) / 2.54;
257 int32_t iu =
KiROUND( Clamp<double>( -int_limit, aValue, int_limit ) * 2.54 );
262 return KiROUND( (
double) iu / 10.0 ) * 10;
269 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
270 return value == aProps.end() ? aDefault : wxAtoi( value->second );
277 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
279 if( value == aProps.end() )
283 std::istringstream istr( (
const char*) value->second.mb_str() );
284 istr.imbue( std::locale::classic() );
295 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
297 if( value == aProps.end() )
300 return value->second ==
"T" || value->second ==
"TRUE";
305 const wxString& aKey,
const wxString& aDefault )
307 const wxString& value =
ReadString( aProps, aKey, aDefault );
311 if( !value.EndsWith(
"mil", &prefix ) )
313 wxLogError(
_(
"Unit '%s' does not end with 'mil'." ), value );
319 if( !prefix.ToCDouble( &mils ) )
321 wxLogError(
_(
"Cannot convert '%s' to double." ), prefix );
330 const wxString& aKey,
const wxString& aDefault )
332 const auto& utf8Value = aProps.find( wxString(
"%UTF8%" ) + aKey );
334 if( utf8Value != aProps.end() )
335 return utf8Value->second;
337 const auto& value = aProps.find( aKey );
339 if( value != aProps.end() )
340 return value->second;
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
static const CFB::COMPOUND_FILE_ENTRY * FindStreamSingleLevel(const CFB::CompoundFileReader &aReader, const CFB::COMPOUND_FILE_ENTRY *aEntry, const std::string aName, const bool aIsStream)
wxString AltiumPropertyToKiCadString(const wxString &aString)
const CFB::CompoundFileReader & GetCompoundFileReader() const
std::vector< char > m_buffer
std::unique_ptr< CFB::CompoundFileReader > m_reader
ALTIUM_COMPOUND_FILE(const wxString &aFilePath)
Open a CFB file.
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
size_t GetRemainingBytes() const
std::map< wxString, wxString > ReadProperties()
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
std::unique_ptr< char[]> m_content
static double ReadDouble(const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
static int32_t ConvertToKicadUnit(const double aValue)
ALTIUM_PARSER(const ALTIUM_COMPOUND_FILE &aFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
static bool ReadBool(const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
#define THROW_IO_ERROR(msg)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".