28#include <compoundfilereader.h>
35#include <wx/translation.h>
39std::string
FormatPath(
const std::vector<std::string>& aVectorPath )
41 return std::accumulate( aVectorPath.cbegin(), aVectorPath.cend(), std::string(),
42 [](
const std::string& ss,
const std::string& s )
44 return ss.empty() ? s : ss +
'\\' + s;
52 FILE* fp = wxFopen( aFilePath,
"rb" );
56 THROW_IO_ERROR( wxString::Format(
_(
"Cannot open file '%s'." ), aFilePath ) );
59 fseek( fp, 0, SEEK_END );
60 long len = ftell( fp );
71 fseek( fp, 0, SEEK_SET );
73 size_t bytesRead = fread(
m_buffer.data(),
sizeof(
unsigned char ), len, fp );
76 if(
static_cast<size_t>( len ) != bytesRead )
85 catch( CFB::CFBException& exception )
95 memcpy(
m_buffer.data(), aBuffer, aLen );
101 catch( CFB::CFBException& exception )
108std::unique_ptr<ALTIUM_COMPOUND_FILE>
111 wxCHECK( cfe.size >= 1,
nullptr );
113 size_t streamSize = cfe.size;
114 wxMemoryBuffer buffer( streamSize );
115 buffer.SetDataLen( streamSize );
122 if( buffer[0] == 0x02 )
124 wxMemoryInputStream memoryInputStream( buffer.GetData(), streamSize );
125 memoryInputStream.SeekI( 1, wxFromStart );
127 wxZlibInputStream zlibInputStream( memoryInputStream );
128 wxMemoryOutputStream decodedPcbLibStream;
129 decodedPcbLibStream << zlibInputStream;
131 wxStreamBuffer* outStream = decodedPcbLibStream.GetOutputStreamBuffer();
133 return std::make_unique<ALTIUM_COMPOUND_FILE>( outStream->GetBufferStart(),
134 outStream->GetIntPosition() );
136 else if( buffer[0] == 0x00 )
138 return std::make_unique<ALTIUM_COMPOUND_FILE>(
139 reinterpret_cast<uint8_t*
>( buffer.GetData() ) + 1, streamSize - 1 );
143 wxFAIL_MSG( wxString::Format(
"Altium IntLib unknown header: %02x %02x %02x %02x %02x",
144 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4] ) );
160std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>
169 return { wxEmptyString,
nullptr };
171 return { it->first, it->second };
175const CFB::COMPOUND_FILE_ENTRY*
177 const std::string aName,
const bool aIsStream )
const
182 const CFB::COMPOUND_FILE_ENTRY* ret =
nullptr;
185 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string& dir,
191 if(
m_reader->IsStream( entry ) == aIsStream )
193 std::string name = UTF16ToUTF8( entry->name );
194 if( name == aName.c_str() )
207std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*>
210 const CFB::COMPOUND_FILE_ENTRY* root = aStart ? aStart :
m_reader->GetRootEntry();
215 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> folders;
217 m_reader->EnumFiles( root, 1, [&](
const CFB::COMPOUND_FILE_ENTRY* tentry,
const CFB::utf16string&,
int ) ->
int
219 wxString dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
225 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string&,
int ) ->
int
227 std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
229 if(
m_reader->IsStream( entry ) && fileName == L
"Data" )
230 folders[dirName] = entry;
242std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*>
245 const CFB::COMPOUND_FILE_ENTRY* root =
m_reader->GetRootEntry();
250 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> files;
254 [&](
const CFB::COMPOUND_FILE_ENTRY* tentry,
const CFB::utf16string& dir,
260 std::wstring dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
262 if( dirName != aDir )
267 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string&,
270 if( m_reader->IsStream( entry ) )
272 std::wstring fileName =
273 UTF16ToWstring( entry->name, entry->nameLen );
275 files[fileName] = entry;
287const CFB::COMPOUND_FILE_ENTRY*
289 const std::vector<std::string>& aStreamPath )
const
297 auto it = aStreamPath.cbegin();
299 while( aStart !=
nullptr )
301 const std::string&
name = *it;
303 if( ++it == aStreamPath.cend() )
319const CFB::COMPOUND_FILE_ENTRY*
334 const CFB::COMPOUND_FILE_ENTRY* root =
m_reader->GetRootEntry();
340 [
this](
const CFB::COMPOUND_FILE_ENTRY* tentry,
const CFB::utf16string& dir,
347 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string&,
int ) ->
int
349 std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
351 if( m_reader->IsStream( entry ) && fileName == L
"Parameters" )
353 ALTIUM_PARSER parametersReader( *this, entry );
354 std::map<wxString, wxString> parameterProperties =
355 parametersReader.ReadProperties();
357 wxString key = ALTIUM_PARSER::ReadString(
358 parameterProperties, wxT(
"PATTERN" ), wxT(
"" ) );
359 wxString fpName = ALTIUM_PARSER::ReadUnicodeString(
360 parameterProperties, wxT(
"PATTERN" ), wxT(
"" ) );
362 m_libFootprintDirNameCache[key] = fpName;
363 m_libFootprintNameCache[fpName] = tentry;
374 const CFB::COMPOUND_FILE_ENTRY* aEntry )
377 m_size =
static_cast<size_t>( aEntry->size );
398 std::function<std::map<wxString, wxString>(
const std::string& )> handleBinaryData )
401 std::map<wxString, wxString>
kv;
403 uint32_t length = Read<uint32_t>();
404 bool isBinary = ( length & 0xff000000 ) != 0;
406 length &= 0x00ffffff;
421 bool hasNullByte =
m_pos[length - 1] ==
'\0';
425 wxLogError(
_(
"Missing null byte at end of property list. Imported data might be "
426 "malformed or missing." ) );
431 std::string str = std::string(
m_pos, length - ( hasNullByte ? 1 : 0 ) );
436 return handleBinaryData( str );
439 std::size_t token_end = 0;
441 while( token_end < str.size() && token_end != std::string::npos )
443 std::size_t token_start = str.find(
'|', token_end );
444 std::size_t token_equal = str.find(
'=', token_start );
445 token_end = str.find(
'|', token_start + 1 );
447 if( token_equal >= token_end )
452 if( token_end == std::string::npos )
454 token_end = str.size() + 1;
457 std::string keyS = str.substr( token_start + 1, token_equal - token_start - 1 );
458 std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
462 wxString key( keyS.c_str(), wxConvISO8859_1 );
464 wxString canonicalKey = key.Trim(
false ).Trim(
true ).MakeUpper();
468 if( canonicalKey.StartsWith(
"%UTF8%" ) )
469 value = wxString( valueS.c_str(), wxConvUTF8 );
471 value = wxString( valueS.c_str(), wxConvISO8859_1 );
473 if( canonicalKey != wxS(
"PATTERN" ) && canonicalKey != wxS(
"SOURCEFOOTPRINTLIBRARY" ) )
477 value.Replace( wxT(
"ÿ" ), wxT(
" " ) );
480 if( canonicalKey == wxT(
"DESIGNATOR" )
481 || canonicalKey == wxT(
"NAME" )
482 || canonicalKey == wxT(
"TEXT" ) )
487 kv.insert( { canonicalKey, value.Trim() } );
496 constexpr double int_limit = ( std::numeric_limits<int>::max() - 10 ) / 2.54;
498 int32_t iu =
KiROUND( Clamp<double>( -int_limit, aValue, int_limit ) * 2.54 );
503 return KiROUND( (
double) iu / 10.0 ) * 10;
510 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
511 return value == aProps.end() ? aDefault : wxAtoi( value->second );
518 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
520 if( value == aProps.end() )
524 std::istringstream istr( (
const char*) value->second.mb_str() );
525 istr.imbue( std::locale::classic() );
536 const std::map<wxString, wxString>::const_iterator& value = aProps.find( aKey );
538 if( value == aProps.end() )
541 return value->second ==
"T" || value->second ==
"TRUE";
546 const wxString& aKey,
const wxString& aDefault )
548 const wxString& value =
ReadString( aProps, aKey, aDefault );
552 if( !value.EndsWith(
"mil", &prefix ) )
554 wxLogError(
_(
"Unit '%s' does not end with 'mil'." ), value );
558 prefix.StartsWith(
"+", &prefix );
562 if( !prefix.ToCDouble( &mils ) )
564 wxLogError(
_(
"Cannot convert '%s' to double." ), prefix );
573 const wxString& aKey,
const wxString& aDefault )
575 const auto& utf8Value = aProps.find( wxString(
"%UTF8%" ) + aKey );
577 if( utf8Value != aProps.end() )
578 return utf8Value->second;
580 const auto& value = aProps.find( aKey );
582 if( value != aProps.end() )
583 return value->second;
590 const wxString& aKey,
const wxString& aDefault )
592 const auto& unicodeFlag = aProps.find( wxS(
"UNICODE" ) );
594 if( unicodeFlag != aProps.end() && unicodeFlag->second.Contains( wxS(
"EXISTS" ) ) )
596 const auto& unicodeValue = aProps.find( wxString(
"UNICODE__" ) + aKey );
598 if( unicodeValue != aProps.end() )
600 wxArrayString arr = wxSplit( unicodeValue->second,
',',
'\0' );
603 for( wxString part : arr )
604 out += wxString(
wchar_t( wxAtoi( part ) ) );
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
wxString AltiumPropertyToKiCadString(const wxString &aString)
std::map< wxString, wxString > ListLibFootprints()
const CFB::CompoundFileReader & GetCompoundFileReader() const
std::unique_ptr< ALTIUM_COMPOUND_FILE > DecodeIntLibStream(const CFB::COMPOUND_FILE_ENTRY &cfe)
const CFB::COMPOUND_FILE_ENTRY * FindStreamSingleLevel(const CFB::COMPOUND_FILE_ENTRY *aEntry, const std::string aName, const bool aIsStream) const
std::map< wxString, const CFB::COMPOUND_FILE_ENTRY * > EnumDir(const std::wstring &aDir) const
std::vector< char > m_buffer
std::unique_ptr< CFB::CompoundFileReader > m_reader
ALTIUM_COMPOUND_FILE(const wxString &aFilePath)
Open a CFB file.
std::map< wxString, const CFB::COMPOUND_FILE_ENTRY * > GetLibSymbols(const CFB::COMPOUND_FILE_ENTRY *aStart) const
std::map< wxString, const CFB::COMPOUND_FILE_ENTRY * > m_libFootprintNameCache
std::tuple< wxString, const CFB::COMPOUND_FILE_ENTRY * > FindLibFootprintDirName(const wxString &aFpUnicodeName)
void cacheLibFootprintNames()
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
std::map< wxString, wxString > m_libFootprintDirNameCache
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
size_t GetRemainingBytes() const
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
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)
static wxString ReadUnicodeString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &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".