28#include <compoundfilereader.h>
36#include <wx/translation.h>
40std::string
FormatPath(
const std::vector<std::string>& aVectorPath )
42 return std::accumulate( aVectorPath.cbegin(), aVectorPath.cend(), std::string(),
43 [](
const std::string& ss,
const std::string& s )
45 return ss.empty() ? s : ss +
'\\' + s;
58 FILE* fp = wxFopen( aFilePath,
"rb" );
62 THROW_IO_ERROR( wxString::Format(
_(
"Cannot open file '%s'." ), aFilePath ) );
65 fseek( fp, 0, SEEK_END );
66 long len = ftell( fp );
77 fseek( fp, 0, SEEK_SET );
79 size_t bytesRead = fread(
m_buffer.data(),
sizeof(
unsigned char ), len, fp );
82 if(
static_cast<size_t>( len ) != bytesRead )
91 catch( CFB::CFBException& exception )
107 memcpy(
m_buffer.data(), aBuffer, aLen );
113 catch( CFB::CFBException& exception )
123 wxCHECK( aOutput,
false );
124 wxCHECK( cfe.size >= 1,
false );
126 size_t streamSize = cfe.size;
127 wxMemoryBuffer buffer( streamSize );
128 buffer.SetDataLen( streamSize );
135 if( buffer[0] == 0x02 )
137 wxMemoryInputStream memoryInputStream( buffer.GetData(), streamSize );
138 memoryInputStream.SeekI( 1, wxFromStart );
140 wxZlibInputStream zlibInputStream( memoryInputStream );
141 wxMemoryOutputStream decodedPcbLibStream;
142 decodedPcbLibStream << zlibInputStream;
144 wxStreamBuffer* outStream = decodedPcbLibStream.GetOutputStreamBuffer();
145 aOutput->
InitFromBuffer( outStream->GetBufferStart(), outStream->GetIntPosition() );
148 else if( buffer[0] == 0x00 )
150 aOutput->
InitFromBuffer(
static_cast<uint8_t*
>( buffer.GetData() ) + 1, streamSize - 1 );
155 wxFAIL_MSG( wxString::Format(
"Altium IntLib unknown header: %02x %02x %02x %02x %02x",
156 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4] ) );
163const CFB::COMPOUND_FILE_ENTRY*
165 const std::string aName,
const bool aIsStream )
const
170 const CFB::COMPOUND_FILE_ENTRY* ret =
nullptr;
173 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string& dir,
179 if(
m_reader->IsStream( entry ) == aIsStream )
181 std::string name = UTF16ToUTF8( entry->name );
182 if( name == aName.c_str() )
195std::map<wxString, ALTIUM_SYMBOL_DATA>
198 const CFB::COMPOUND_FILE_ENTRY* root = aStart ? aStart :
m_reader->GetRootEntry();
203 std::map<wxString, ALTIUM_SYMBOL_DATA> folders;
205 m_reader->EnumFiles( root, 1, [&](
const CFB::COMPOUND_FILE_ENTRY* tentry,
206 const CFB::utf16string&,
int ) ->
int
208 wxString dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
214 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
215 const CFB::utf16string&,
int ) ->
int
217 std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
219 if(
m_reader->IsStream( entry ) && fileName == L
"Data" )
220 folders[dirName].m_symbol = entry;
222 if(
m_reader->IsStream( entry ) && fileName == L
"PinFrac" )
223 folders[dirName].m_pinsFrac = entry;
225 if(
m_reader->IsStream( entry ) && fileName == L
"PinWideText" )
226 folders[dirName].m_pinsWideText = entry;
228 if(
m_reader->IsStream( entry ) && fileName == L
"PinTextData" )
229 folders[dirName].m_pinsTextData = entry;
241std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*>
244 const CFB::COMPOUND_FILE_ENTRY* root =
m_reader->GetRootEntry();
249 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> files;
253 [&](
const CFB::COMPOUND_FILE_ENTRY* tentry,
const CFB::utf16string& dir,
259 std::wstring dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
261 if( dirName != aDir )
266 [&](
const CFB::COMPOUND_FILE_ENTRY* entry,
const CFB::utf16string&,
269 if( m_reader->IsStream( entry ) )
271 std::wstring fileName =
272 UTF16ToWstring( entry->name, entry->nameLen );
274 files[fileName] = entry;
286const CFB::COMPOUND_FILE_ENTRY*
288 const std::vector<std::string>& aStreamPath )
const
296 auto it = aStreamPath.cbegin();
298 while( aStart !=
nullptr )
300 const std::string&
name = *it;
302 if( ++it == aStreamPath.cend() )
318const CFB::COMPOUND_FILE_ENTRY*
326 const CFB::COMPOUND_FILE_ENTRY* aEntry )
329 m_size =
static_cast<size_t>( aEntry->size );
350 std::function<std::map<wxString, wxString>(
const std::string& )> handleBinaryData )
353 static wxCSConv convISO8859_1 = wxConvISO8859_1;
355 std::map<wxString, wxString>
kv;
357 uint32_t length = Read<uint32_t>();
358 bool isBinary = ( length & 0xff000000 ) != 0;
360 length &= 0x00ffffff;
375 bool hasNullByte =
m_pos[length - 1] ==
'\0';
377 if( !hasNullByte && !isBinary )
379 wxLogTrace(
"ALTIUM", wxT(
"Missing null byte at end of property list. Imported data "
380 "might be malformed or missing." ) );
385 std::string str = std::string(
m_pos, length - ( hasNullByte ? 1 : 0 ) );
390 return handleBinaryData( str );
393 std::size_t token_end = 0;
395 while( token_end < str.size() && token_end != std::string::npos )
397 std::size_t token_start = str.find(
'|', token_end );
398 std::size_t token_equal = str.find(
'=', token_end );
399 std::size_t key_start;
401 if( token_start <= token_equal )
403 key_start = token_start + 1;
408 key_start = token_end;
411 token_end = str.find(
'|', key_start );
413 if( token_equal >= token_end )
418 if( token_end == std::string::npos )
420 token_end = str.size() + 1;
423 std::string keyS = str.substr( key_start, token_equal - key_start );
424 std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
428 wxString key( keyS.c_str(), convISO8859_1 );
431 wxString canonicalKey = key.Trim(
false ).Trim(
true ).MakeUpper();
436 if( canonicalKey.StartsWith(
"%UTF8%" ) )
437 value = wxString( valueS.c_str(), wxConvUTF8 );
439 value = wxString( valueS.c_str(), convISO8859_1 );
441 if( canonicalKey != wxS(
"PATTERN" ) && canonicalKey != wxS(
"SOURCEFOOTPRINTLIBRARY" ) )
445 value.Replace( wxT(
"ÿ" ), wxT(
" " ) );
448 if( canonicalKey == wxT(
"DESIGNATOR" )
449 || canonicalKey == wxT(
"NAME" )
450 || canonicalKey == wxT(
"TEXT" ) )
452 if(
kv[ wxT(
"RECORD" ) ] != wxT(
"4" ) )
456 kv.insert( { canonicalKey, value.Trim() } );
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
wxString AltiumPropertyToKiCadString(const wxString &aString)
size_t GetRemainingBytes() const
std::unique_ptr< char[]> m_content
ALTIUM_BINARY_PARSER(const ALTIUM_COMPOUND_FILE &aFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
ALTIUM_COMPOUND_FILE()
Create an uninitialized file for two-step initialization (e.g. with InitFromBuffer)
const CFB::CompoundFileReader & GetCompoundFileReader() const
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
void InitFromBuffer(const void *aBuffer, size_t aLen)
Load a CFB file from memory; may throw an IO_ERROR.
std::vector< char > m_buffer
std::unique_ptr< CFB::CompoundFileReader > m_reader
std::map< wxString, ALTIUM_SYMBOL_DATA > GetLibSymbols(const CFB::COMPOUND_FILE_ENTRY *aStart) const
bool DecodeIntLibStream(const CFB::COMPOUND_FILE_ENTRY &cfe, ALTIUM_COMPOUND_FILE *aOutput)
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
#define THROW_IO_ERROR(msg)