KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_pcb_compound_file.cpp
Go to the documentation of this file.
1/*
2 * This program is part of KiCad, a free EDA CAD application.
3 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
20#include <utf.h>
21
22#include <wx/string.h>
23
24#include <compoundfilereader.h>
25#include <map>
26
28 : ALTIUM_COMPOUND_FILE( aFilePath )
29{
30}
31
32ALTIUM_PCB_COMPOUND_FILE::ALTIUM_PCB_COMPOUND_FILE( const void* aBuffer, size_t aLen )
33 : ALTIUM_COMPOUND_FILE( aBuffer, aLen )
34{
35}
36
37
39{
40}
41
42std::map<wxString, wxString> ALTIUM_PCB_COMPOUND_FILE::ListLibFootprints()
43{
44 if( m_libFootprintDirNameCache.empty() )
46
48}
49
50
51std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>
53{
54 if( m_libFootprintNameCache.empty() )
56
57 auto it = m_libFootprintNameCache.find( aFpUnicodeName );
58
59 if( it == m_libFootprintNameCache.end() )
60 return { wxEmptyString, nullptr };
61
62 return { it->first, it->second };
63}
64
65
66const std::pair<AMODEL, std::vector<char>>* ALTIUM_PCB_COMPOUND_FILE::GetLibModel( const wxString& aModelName ) const
67{
68 auto it = m_libModelsCache.find( aModelName );
69
70 if( it == m_libModelsCache.end() )
71 return nullptr;
72
73 return &it->second;
74}
75
76
78{
81
82 if( !m_reader )
83 return;
84
85 const CFB::COMPOUND_FILE_ENTRY* root = m_reader->GetRootEntry();
86
87 if( !root )
88 return;
89
90 m_reader->EnumFiles( root, 1,
91 [this]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string& dir, int level ) -> int
92 {
93 if( m_reader->IsStream( tentry ) )
94 return 0;
95
96 m_reader->EnumFiles( tentry, 1,
97 [&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string&, int ) -> int
98 {
99 std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
100
101 if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
102 {
103 ALTIUM_BINARY_PARSER parametersReader( *this, entry );
104 std::map<wxString, wxString> parameterProperties =
105 parametersReader.ReadProperties();
106
107 wxString key = ALTIUM_PROPS_UTILS::ReadString(
108 parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
109 wxString fpName = ALTIUM_PROPS_UTILS::ReadUnicodeString(
110 parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
111
112 m_libFootprintDirNameCache[key] = fpName;
113 m_libFootprintNameCache[fpName] = tentry;
114 }
115
116 return 0;
117 } );
118 return 0;
119 } );
120}
121
122
124{
125 const CFB::COMPOUND_FILE_ENTRY* models_root = nullptr;
126 const CFB::COMPOUND_FILE_ENTRY* models_data = nullptr;
127 bool found = false;
128
129 if( !m_reader || !m_libModelsCache.empty() )
130 return false;
131
132 models_data = FindStream( { "Library", "Models", "Data" } );
133
134 if( !models_data )
135 return false;
136
137 ALTIUM_BINARY_PARSER parser( *this, models_data );
138
139 if( parser.GetRemainingBytes() == 0 )
140 return false;
141
142 std::vector<AMODEL> models;
143
144 // First, we parse and extract the model data from the Data stream
145 while( parser.GetRemainingBytes() >= 4 )
146 {
147 AMODEL elem( parser );
148 models.push_back( elem );
149 }
150
151 // Next, we need the model directory entry to read the compressed model streams
152 m_reader->EnumFiles( m_reader->GetRootEntry(), 2, [&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir, int ) -> int
153 {
154 if( found )
155 return 1;
156
157 if( m_reader->IsStream( entry ) )
158 return 0;
159
160 std::string dir_str = UTF16ToUTF8( dir.c_str() );
161 std::string entry_str = UTF16ToUTF8( entry->name );
162
163 if( dir_str.compare( "Library" ) == 0 && entry_str.compare( "Models" ) == 0 )
164 {
165 models_root = entry;
166 found = true;
167 return 1;
168 }
169
170 return 0;
171 });
172
173 if( !models_root )
174 return false;
175
176 m_reader->EnumFiles(
177 models_root, 1,
178 [&]( const CFB::COMPOUND_FILE_ENTRY* stepEntry, const CFB::utf16string&, int ) -> int
179 {
180 long fileNumber;
181 wxString fileName = UTF16ToUTF8( stepEntry->name, stepEntry->nameLen );
182
183 if( !fileName.ToLong( &fileNumber ) )
184 return 0;
185
186 if( !m_reader->IsStream( stepEntry ) || fileNumber >= long( models.size() ) )
187 return 0;
188
189 size_t stepSize = static_cast<size_t>( stepEntry->size );
190 std::vector<char> stepContent( stepSize );
191
192 // read file into buffer
193 m_reader->ReadFile( stepEntry, 0, stepContent.data(), stepSize );
194
195 if( stepContent.empty() )
196 return 0;
197
198 // We store the models in their original compressed form so as to speed the caching process
199 // When we parse an individual footprint, we decompress and recompress the model data into
200 // our format
201 wxString modelName = models[fileNumber].id;
202 m_libModelsCache.emplace( modelName, std::make_pair( std::move( models[fileNumber] ),
203 std::move( stepContent ) ) );
204 return 0;
205 } );
206
207 return true;
208}
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)