KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_pcb_compound_file.cpp
Go to the documentation of this file.
2#include <utf.h>
3
4#include <wx/string.h>
5
6#include <compoundfilereader.h>
7#include <map>
8
10 : ALTIUM_COMPOUND_FILE( aFilePath )
11{
12}
13
14ALTIUM_PCB_COMPOUND_FILE::ALTIUM_PCB_COMPOUND_FILE( const void* aBuffer, size_t aLen )
15 : ALTIUM_COMPOUND_FILE( aBuffer, aLen )
16{
17}
18
19
21{
22}
23
24std::map<wxString, wxString> ALTIUM_PCB_COMPOUND_FILE::ListLibFootprints()
25{
26 if( m_libFootprintDirNameCache.empty() )
28
30}
31
32
33std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>
35{
36 if( m_libFootprintNameCache.empty() )
38
39 auto it = m_libFootprintNameCache.find( aFpUnicodeName );
40
41 if( it == m_libFootprintNameCache.end() )
42 return { wxEmptyString, nullptr };
43
44 return { it->first, it->second };
45}
46
47
48const std::pair<AMODEL, std::vector<char>>* ALTIUM_PCB_COMPOUND_FILE::GetLibModel( const wxString& aModelName ) const
49{
50 auto it = m_libModelsCache.find( aModelName );
51
52 if( it == m_libModelsCache.end() )
53 return nullptr;
54
55 return &it->second;
56}
57
58
60{
63
64 if( !m_reader )
65 return;
66
67 const CFB::COMPOUND_FILE_ENTRY* root = m_reader->GetRootEntry();
68
69 if( !root )
70 return;
71
72 m_reader->EnumFiles( root, 1,
73 [this]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string& dir, int level ) -> int
74 {
75 if( m_reader->IsStream( tentry ) )
76 return 0;
77
78 m_reader->EnumFiles( tentry, 1,
79 [&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string&, int ) -> int
80 {
81 std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
82
83 if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
84 {
85 ALTIUM_BINARY_PARSER parametersReader( *this, entry );
86 std::map<wxString, wxString> parameterProperties =
87 parametersReader.ReadProperties();
88
89 wxString key = ALTIUM_PROPS_UTILS::ReadString(
90 parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
91 wxString fpName = ALTIUM_PROPS_UTILS::ReadUnicodeString(
92 parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
93
94 m_libFootprintDirNameCache[key] = fpName;
95 m_libFootprintNameCache[fpName] = tentry;
96 }
97
98 return 0;
99 } );
100 return 0;
101 } );
102}
103
104
106{
107 const CFB::COMPOUND_FILE_ENTRY* models_root = nullptr;
108 const CFB::COMPOUND_FILE_ENTRY* models_data = nullptr;
109 bool found = false;
110
111 if( !m_reader || !m_libModelsCache.empty() )
112 return false;
113
114 models_data = FindStream( { "Library", "Models", "Data" } );
115
116 if( !models_data )
117 return false;
118
119 ALTIUM_BINARY_PARSER parser( *this, models_data );
120
121 if( parser.GetRemainingBytes() == 0 )
122 return false;
123
124 std::vector<AMODEL> models;
125
126 // First, we parse and extract the model data from the Data stream
127 while( parser.GetRemainingBytes() >= 4 )
128 {
129 AMODEL elem( parser );
130 models.push_back( elem );
131 }
132
133 // Next, we need the model directory entry to read the compressed model streams
134 m_reader->EnumFiles( m_reader->GetRootEntry(), 2, [&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir, int ) -> int
135 {
136 if( found )
137 return 1;
138
139 if( m_reader->IsStream( entry ) )
140 return 0;
141
142 std::string dir_str = UTF16ToUTF8( dir.c_str() );
143 std::string entry_str = UTF16ToUTF8( entry->name );
144
145 if( dir_str.compare( "Library" ) == 0 && entry_str.compare( "Models" ) == 0 )
146 {
147 models_root = entry;
148 found = true;
149 return 1;
150 }
151
152 return 0;
153 });
154
155 if( !models_root )
156 return false;
157
158 m_reader->EnumFiles(
159 models_root, 1,
160 [&]( const CFB::COMPOUND_FILE_ENTRY* stepEntry, const CFB::utf16string&, int ) -> int
161 {
162 long fileNumber;
163 wxString fileName = UTF16ToUTF8( stepEntry->name, stepEntry->nameLen );
164
165 if( !fileName.ToLong( &fileNumber ) )
166 return 0;
167
168 if( !m_reader->IsStream( stepEntry ) || fileNumber >= long( models.size() ) )
169 return 0;
170
171 size_t stepSize = static_cast<size_t>( stepEntry->size );
172 std::vector<char> stepContent( stepSize );
173
174 // read file into buffer
175 m_reader->ReadFile( stepEntry, 0, stepContent.data(), stepSize );
176
177 if( stepContent.empty() )
178 return 0;
179
180 // We store the models in their original compressed form so as to speed the caching process
181 // When we parse an individual footprint, we decompress and recompress the model data into
182 // our format
183 wxString modelName = models[fileNumber].id;
184 m_libModelsCache.emplace( modelName, std::make_pair( std::move( models[fileNumber] ),
185 std::move( stepContent ) ) );
186 return 0;
187 } );
188
189 return true;
190}
size_t GetRemainingBytes() const
std::unique_ptr< CFB::CompoundFileReader > m_reader
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
friend class ALTIUM_PCB_COMPOUND_FILE
std::map< wxString, wxString > ListLibFootprints()
const std::pair< AMODEL, std::vector< char > > * GetLibModel(const wxString &aModelID) const
std::map< wxString, wxString > m_libFootprintDirNameCache
std::map< wxString, std::pair< AMODEL, std::vector< char > > > m_libModelsCache
std::map< wxString, const CFB::COMPOUND_FILE_ENTRY * > m_libFootprintNameCache
std::tuple< wxString, const CFB::COMPOUND_FILE_ENTRY * > FindLibFootprintDirName(const wxString &aFpUnicodeName)