KiCad PCB EDA Suite
Loading...
Searching...
No Matches
remote_symbol_import_job.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
23
24#include <eeschema_settings.h>
25#include <string_view>
27#include <pgm_base.h>
30
31#include <wx/intl.h>
32
33
34namespace
35{
36bool validateSymbolPayload( const std::vector<uint8_t>& aPayload, const wxString& aExpectedSymbolName,
37 wxString& aError )
38{
39 if( aExpectedSymbolName.IsEmpty() )
40 return true;
41
42 if( aPayload.empty() )
43 {
44 aError = _( "Downloaded symbol payload was empty." );
45 return false;
46 }
47
48 std::string_view payload( reinterpret_cast<const char*>( aPayload.data() ), aPayload.size() );
49
50 if( payload.find( "(kicad_symbol_lib" ) == std::string_view::npos )
51 {
52 aError = _( "Downloaded symbol payload was not a KiCad symbol library." );
53 return false;
54 }
55
56 const std::string symbolToken =
57 wxString::Format( wxS( "(symbol \"%s\"" ), aExpectedSymbolName ).ToStdString();
58
59 if( payload.find( symbolToken ) == std::string_view::npos )
60 {
61 aError = wxString::Format(
62 _( "Downloaded symbol payload did not include expected symbol '%s'." ),
63 aExpectedSymbolName );
64 return false;
65 }
66
67 return true;
68}
69} // namespace
70
71
73 REMOTE_SYMBOL_DOWNLOAD_MANAGER* aDownloader ) :
74 m_frame( aFrame ),
75 m_downloader( aDownloader )
76{
77 if( !m_downloader )
78 {
79 m_ownedDownloader = std::make_unique<REMOTE_SYMBOL_DOWNLOAD_MANAGER>();
81 }
82}
83
84
86 const REMOTE_SYMBOL_IMPORT_CONTEXT& aContext,
87 const REMOTE_PROVIDER_PART_MANIFEST& aManifest,
88 bool aPlaceSymbol, wxString& aError )
89{
90 aError.clear();
91
93
94 if( !settings )
95 {
96 aError = _( "Unable to load schematic settings." );
97 return false;
98 }
99
100 wxFileName baseDir;
101
102 if( !EnsureRemoteDestinationRoot( baseDir, aError ) )
103 return false;
104
105 long long remainingBudget = aProvider.max_download_bytes;
106 const bool addToGlobal = settings->m_RemoteSymbol.add_to_global_table;
107 const bool strictLibraryTables = m_frame != nullptr;
108 const wxString prefix = RemoteLibraryPrefix();
109 bool importedSymbol = false;
110 wxString placedNickname;
111 wxString placedSymbolName;
112
113 for( const REMOTE_PROVIDER_PART_ASSET& asset : aManifest.assets )
114 {
116
117 if( !downloader().DownloadAndVerify( aProvider, asset, remainingBudget, fetched, aError ) )
118 return false;
119
120 remainingBudget -= asset.size_bytes;
121
122 if( asset.asset_type == wxS( "symbol" ) )
123 {
124 wxFileName symbolDir = baseDir;
125 symbolDir.AppendDir( wxS( "symbols" ) );
126
127 const wxString libraryName = SanitizeRemoteFileComponent(
128 asset.target_library.IsEmpty() ? aContext.library_name : asset.target_library,
129 wxS( "symbols" ), true );
130 const wxString symbolName =
131 asset.target_name.IsEmpty() ? aContext.symbol_name : asset.target_name;
132 const wxString nickname = prefix + wxS( "_" ) + libraryName;
133
134 wxFileName outFile( symbolDir );
135 outFile.SetFullName( nickname + wxS( ".kicad_sym" ) );
136
137 if( !validateSymbolPayload( fetched.payload, symbolName, aError ) )
138 return false;
139
140 if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
141 return false;
142
143 if( strictLibraryTables )
144 {
146 addToGlobal, true, aError ) )
147 return false;
148
152 }
153
154 importedSymbol = true;
155 placedNickname = nickname;
156 placedSymbolName = symbolName;
157 }
158 else if( asset.asset_type == wxS( "footprint" ) )
159 {
160 wxFileName fpRoot = baseDir;
161 fpRoot.AppendDir( wxS( "footprints" ) );
162
163 const wxString libraryName = SanitizeRemoteFileComponent(
164 asset.target_library.IsEmpty() ? asset.name : asset.target_library,
165 wxS( "footprints" ), true );
166 const wxString nickname = prefix + wxS( "_" ) + libraryName;
167
168 wxFileName libDir = fpRoot;
169 libDir.AppendDir( nickname + wxS( ".pretty" ) );
170
171 wxString fileName = SanitizeRemoteFileComponent(
172 asset.target_name.IsEmpty() ? asset.name : asset.target_name,
173 wxS( "footprint" ) );
174
175 if( !fileName.Lower().EndsWith( wxS( ".kicad_mod" ) ) )
176 fileName += wxS( ".kicad_mod" );
177
178 wxFileName outFile( libDir );
179 outFile.SetFullName( fileName );
180
181 if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
182 return false;
183
184 if( strictLibraryTables )
185 {
187 addToGlobal, true, aError ) )
188 return false;
189
193 }
194 }
195 else if( asset.asset_type == wxS( "3dmodel" ) )
196 {
197 wxFileName modelDir = baseDir;
198 modelDir.AppendDir( prefix + wxS( "_3d" ) );
199
200 wxString fileName = SanitizeRemoteFileComponent(
201 asset.target_name.IsEmpty() ? asset.name : asset.target_name,
202 prefix + wxS( "_model" ) );
203
204 wxFileName outFile( modelDir );
205 outFile.SetFullName( fileName );
206
207 if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
208 return false;
209 }
210 else if( asset.asset_type == wxS( "spice" ) )
211 {
212 wxFileName spiceDir = baseDir;
213 spiceDir.AppendDir( prefix + wxS( "_spice" ) );
214
215 wxString fileName = SanitizeRemoteFileComponent(
216 asset.target_name.IsEmpty() ? asset.name : asset.target_name,
217 prefix + wxS( "_model.cir" ) );
218
219 if( !fileName.Lower().EndsWith( wxS( ".cir" ) ) )
220 fileName += wxS( ".cir" );
221
222 wxFileName outFile( spiceDir );
223 outFile.SetFullName( fileName );
224
225 if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
226 return false;
227 }
228 }
229
230 if( aPlaceSymbol )
231 {
232 if( !importedSymbol )
233 {
234 aError = _( "No symbol asset was available to place." );
235 return false;
236 }
237
238 if( !PlaceRemoteDownloadedSymbol( m_frame, placedNickname, placedSymbolName, aError ) )
239 return false;
240 }
241
242 return true;
243}
244
245
REMOTE_PROVIDER_SETTINGS m_RemoteSymbol
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:133
const REMOTE_SYMBOL_DOWNLOAD_MANAGER & downloader() const
std::unique_ptr< REMOTE_SYMBOL_DOWNLOAD_MANAGER > m_ownedDownloader
REMOTE_SYMBOL_DOWNLOAD_MANAGER * m_downloader
REMOTE_SYMBOL_IMPORT_JOB(SCH_EDIT_FRAME *aFrame, REMOTE_SYMBOL_DOWNLOAD_MANAGER *aDownloader=nullptr)
bool Import(const REMOTE_PROVIDER_METADATA &aProvider, const REMOTE_SYMBOL_IMPORT_CONTEXT &aContext, const REMOTE_PROVIDER_PART_MANIFEST &aManifest, bool aPlaceSymbol, wxString &aError)
Schematic editor (Eeschema) main window.
#define _(s)
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
bool PlaceRemoteDownloadedSymbol(SCH_EDIT_FRAME *aFrame, const wxString &aNickname, const wxString &aLibItemName, wxString &aError)
Place a symbol from a remote download into the schematic editor.
bool EnsureRemoteLibraryEntry(LIBRARY_TABLE_TYPE aTableType, const wxFileName &aLibraryPath, const wxString &aNickname, bool aGlobalTable, bool aStrict, wxString &aError)
Add or update a library table entry for a remote download library.
bool WriteRemoteBinaryFile(const wxFileName &aOutput, const std::vector< uint8_t > &aPayload, wxString &aError)
Write binary data to a file, creating parent directories as needed.
bool EnsureRemoteDestinationRoot(wxFileName &aOutDir, wxString &aError)
Resolve and create the configured destination root directory for remote symbol downloads.
wxString RemoteLibraryPrefix()
Return the configured (or default) library prefix for remote downloads, sanitized for use as a filena...
wxString SanitizeRemoteFileComponent(const wxString &aValue, const wxString &aDefault, bool aLower)
Replace non-alphanumeric characters (other than _ - .) with underscores.
T * GetAppSettings(const char *aFilename)
std::vector< REMOTE_PROVIDER_PART_ASSET > assets