KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pluginldr.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 (C) 2015-2016 Cirilo Bernardo <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <iostream>
22#include <sstream>
23#include <wx/dynload.h>
24#include <wx/log.h>
25#include <wx/string.h>
26#include <wx/translation.h>
27
28#include "pluginldr.h"
29
30
36const wxChar* const tracePluginLoader = wxT( "KICAD_PLUGIN_LOADER" );
37
38
40{
41 ok = false;
42 m_getPluginClass = nullptr;
43 m_getClassVersion = nullptr;
44 m_checkClassVersion = nullptr;
45 m_getPluginName = nullptr;
46 m_getVersion = nullptr;
47
48 return;
49}
50
51
53{
54 close();
55 return;
56}
57
58
59bool KICAD_PLUGIN_LDR::open( const wxString& aFullFileName, const char* aPluginClass )
60{
61 m_error.clear();
62
63 if( ok )
64 Close();
65
66 if( aFullFileName.empty() )
67 return false;
68
69 m_fileName.clear();
70
71 m_PluginLoader.Load( aFullFileName, wxDL_LAZY );
72
73 if( !m_PluginLoader.IsLoaded() )
74 {
75 wxLogTrace( tracePluginLoader, wxT( " * could not open file: '%s'" ),
76 aFullFileName.ToUTF8() );
77
78 return false;
79 }
80
81 LINK_ITEM( m_getPluginClass, GET_PLUGIN_CLASS, "GetKicadPluginClass" );
82 LINK_ITEM( m_getClassVersion, GET_CLASS_VERSION, "GetClassVersion" );
83 LINK_ITEM( m_checkClassVersion, CHECK_CLASS_VERSION , "CheckClassVersion" );
84 LINK_ITEM( m_getPluginName, GET_PLUGIN_NAME, "GetKicadPluginName" );
85 LINK_ITEM( m_getVersion, GET_VERSION, "GetPluginVersion" );
86
87#ifdef DEBUG
88 bool fail = false;
89
90 if( !m_getPluginClass )
91 {
92 wxLogTrace( tracePluginLoader,
93 wxT( "%s:%s:%d\n"
94 "incompatible plugin (missing function 'GetKicadPluginClass')" ),
95 __FILE__, __FUNCTION__, __LINE__ );
96
97 fail = true;
98 }
99
100 if( !m_getClassVersion )
101 {
102 if( !fail )
103 {
104 wxLogTrace( tracePluginLoader,
105 wxT( "%s:%s:%d\n"
106 "incompatible plugin (missing function 'GetClassVersion')" ),
107 __FILE__, __FUNCTION__, __LINE__ );
108 fail = true;
109 }
110 else
111 {
112 wxLogTrace( tracePluginLoader, wxT( "missing function 'GetClassVersion'" ) );
113 }
114 }
115
117 {
118 if( !fail )
119 {
120 wxLogTrace( tracePluginLoader,
121 wxT( "%s:%s:%d\n"
122 "incompatible plugin (missing function 'CheckClassVersion')" ),
123 __FILE__, __FUNCTION__, __LINE__ );
124
125 fail = true;
126 }
127 else
128 {
129 wxLogTrace( tracePluginLoader, wxT( "missing function 'CheckClassVersion'" ) );
130 }
131 }
132
133 if( !m_getPluginName )
134 {
135 if( !fail )
136 {
137 wxLogTrace( tracePluginLoader,
138 wxT( "%s:%s:%d\n"
139 "incompatible plugin (missing function 'GetKicadPluginName')" ),
140 __FILE__, __FUNCTION__, __LINE__ );
141
142 fail = true;
143 }
144 else
145 {
146 wxLogTrace( tracePluginLoader, wxT( "missing function 'GetKicadPluginName'" ) );
147 }
148 }
149
150 if( !m_getVersion )
151 {
152 if( !fail )
153 {
154 wxLogTrace( tracePluginLoader,
155 wxT( "%s:%s:%d\n"
156 "incompatible plugin (missing function 'GetVersion')" ),
157 __FILE__, __FUNCTION__, __LINE__ );
158 }
159 else
160 {
161 wxLogTrace( tracePluginLoader, wxT( "missing function 'GetVersion'" ) );
162 }
163 }
164
165#endif
166
169 {
170 m_error = "incompatible plugin interface (missing functions)";
171 close();
172 return false;
173 }
174
175 // note: since 'ok' is not yet set at this point we must use the function
176 // pointers directly rather than invoking the functions exposed by this class
177
178 // check that the Plugin Class matches
179 char const* pclassName = m_getPluginClass();
180
181 if( !pclassName || strcmp( aPluginClass, pclassName ) )
182 {
183 m_error = "Loader type (";
184 m_error.append( aPluginClass );
185 m_error.append( ") does not match Plugin type (" );
186
187 if( pclassName )
188 m_error.append( pclassName );
189 else
190 m_error.append( "nullptr" );
191
192 m_error.append( ")" );
193
194 close();
195 return false;
196 }
197
198 // perform a universally enforced version check (major number must match)
199 unsigned char lMajor;
200 unsigned char lMinor;
201 unsigned char lPatch;
202 unsigned char lRevno;
203 unsigned char pMajor;
204 unsigned char pMinor;
205 unsigned char pPatch;
206 unsigned char pRevno;
207
208 m_getClassVersion( &pMajor, &pMinor, &pPatch, &pRevno );
209 GetLoaderVersion( &lMajor, &lMinor, &lPatch, &lRevno );
210
211 // major version changes by definition are incompatible and that is enforced here.
212 if( pMajor != lMajor )
213 {
214 std::ostringstream ostr;
215 ostr << "Loader Major version (" << lMajor;
216 ostr << ") does not match Plugin Major version (" << pMajor << ")";
217
218 m_error = ostr.str();
219 close();
220 return false;
221 }
222
223 if( !m_checkClassVersion( lMajor, lMinor, lPatch, lRevno ) )
224 {
225 std::ostringstream ostr;
226 ostr << "Plugin Version (" << pMajor << "." << pMinor << "." << pPatch << "." << pRevno;
227 ostr << ") does not support Loader Version (" << pMajor << "." << pMinor;
228 ostr << "." << pPatch << "." << pRevno << ")";
229
230 m_error = ostr.str();
231 close();
232 return false;
233 }
234
235 m_fileName = aFullFileName;
236
237 wxLogTrace( tracePluginLoader,
238 wxT( "%s:%s:%d\n"
239 " * [INFO] opened plugin '%s'" ),
240 __FILE__, __FUNCTION__, __LINE__, m_fileName );
241
242 ok = true;
243
244 // set the plugin info string
246 std::ostringstream ostr;
247 unsigned char r0, r1, r2, r3;
248 GetVersion( &r0, &r1, &r2, &r3 );
249 ostr << ":" << (unsigned int)r0 << "." << (unsigned int)r1;
250 ostr << "." << (unsigned int)r2 << "." << (unsigned int)r3;
251 m_pluginInfo.append( ostr.str() );
252
253 return true;
254}
255
256
258{
259 ok = false;
260 m_getPluginClass = nullptr;
261 m_getClassVersion = nullptr;
262 m_checkClassVersion = nullptr;
263 m_getPluginName = nullptr;
264 m_getVersion = nullptr;
265 m_PluginLoader.Unload();
266
267 return;
268}
269
270
272{
273 m_error.clear();
274
275 if( m_fileName.empty() )
276 return false;
277
278 wxString fname = m_fileName;
279
280 return Open( fname );
281}
282
283
284std::string KICAD_PLUGIN_LDR::GetLastError( void ) const
285{
286 return m_error;
287}
288
289
291{
292 m_error.clear();
293
294 if( !ok && !reopen() )
295 {
296 if( m_error.empty() )
297 m_error = "[INFO] no open plugin / plugin could not be opened";
298
299 return nullptr;
300 }
301
302 if( nullptr == m_getPluginClass )
303 {
304 m_error = "[BUG] GetPluginClass is not linked";
305
306 wxLogTrace( tracePluginLoader, wxT( "%s:%s:%d\n"
307 "%s" ),
308 __FILE__, __FUNCTION__, __LINE__, m_error );;
309
310 return nullptr;
311 }
312
313 return m_getPluginClass();
314}
315
316
317bool KICAD_PLUGIN_LDR::GetClassVersion( unsigned char* Major, unsigned char* Minor,
318 unsigned char* Patch, unsigned char* Revision )
319{
320 m_error.clear();
321
322 if( Major )
323 *Major = 0;
324
325 if( Minor )
326 *Minor = 0;
327
328 if( Patch )
329 *Patch = 0;
330
331 if( Revision )
332 *Revision = 0;
333
334 unsigned char major;
335 unsigned char minor;
336 unsigned char patch;
337 unsigned char revno;
338
339 if( !ok && !reopen() )
340 {
341 if( m_error.empty() )
342 m_error = "[INFO] no open plugin / plugin could not be opened";
343
344 return false;
345 }
346
347 if( nullptr == m_checkClassVersion )
348 {
349 m_error = "[BUG] CheckClassVersion is not linked";
350
351 wxLogTrace( tracePluginLoader, wxT( "%s:%s:%d\n"
352 "%s" ),
353 __FILE__, __FUNCTION__, __LINE__, m_error );;
354
355 return false;
356 }
357
358 m_getClassVersion( &major, &minor, &patch, &revno );
359
360 if( Major )
361 *Major = major;
362
363 if( Minor )
364 *Minor = minor;
365
366 if( Patch )
367 *Patch = patch;
368
369 if( Revision )
370 *Revision = revno;
371
372 return true;
373}
374
375
376bool KICAD_PLUGIN_LDR::CheckClassVersion( unsigned char Major, unsigned char Minor,
377 unsigned char Patch, unsigned char Revision )
378{
379 m_error.clear();
380
381 if( !ok && !reopen() )
382 {
383 if( m_error.empty() )
384 m_error = "[INFO] no open plugin / plugin could not be opened";
385
386 return false;
387 }
388
389 if( nullptr == m_checkClassVersion )
390 {
391 m_error = "[BUG] CheckClassVersion is not linked";
392
393 wxLogTrace( tracePluginLoader, wxT( "%s:%s:%d\n"
394 "%s" ),
395 __FILE__, __FUNCTION__, __LINE__, m_error );;
396
397 return false;
398 }
399
400 return m_checkClassVersion( Major, Minor, Patch, Revision );
401}
402
403
405{
406 m_error.clear();
407
408 if( !ok && !reopen() )
409 {
410 if( m_error.empty() )
411 m_error = "[INFO] no open plugin / plugin could not be opened";
412
413 return nullptr;
414 }
415
416 if( nullptr == m_getPluginName )
417 {
418 m_error = "[BUG] GetKicadPluginName is not linked";
419
420 wxLogTrace( tracePluginLoader, wxT( "%s:%s:%d\n"
421 "%s" ),
422 __FILE__, __FUNCTION__, __LINE__, m_error );;
423
424 return nullptr;
425 }
426
427 return m_getPluginName();
428}
429
430
431bool KICAD_PLUGIN_LDR::GetVersion( unsigned char* Major, unsigned char* Minor,
432 unsigned char* Patch, unsigned char* Revision )
433{
434 m_error.clear();
435
436 if( !ok && !reopen() )
437 {
438 if( m_error.empty() )
439 m_error = "[INFO] no open plugin / plugin could not be opened";
440
441 return false;
442 }
443
444 if( nullptr == m_getVersion )
445 {
446 m_error = "[BUG] GetKicadPluginName is not linked";
447
448 wxLogTrace( tracePluginLoader, wxT( "%s:%s:%d\n"
449 "%s" ),
450 __FILE__, __FUNCTION__, __LINE__, m_error );;
451
452 return false;
453 }
454
455 m_getVersion( Major, Minor, Patch, Revision );
456
457 return true;
458}
459
460
461void KICAD_PLUGIN_LDR::GetPluginInfo( std::string& aPluginInfo )
462{
463 aPluginInfo = m_pluginInfo;
464}
virtual void GetLoaderVersion(unsigned char *Major, unsigned char *Minor, unsigned char *Patch, unsigned char *Revision) const =0
Return the version information of the Plugin Loader for plugin compatibility checking.
CHECK_CLASS_VERSION m_checkClassVersion
Definition pluginldr.h:139
std::string GetLastError(void) const
Return the value of the internal error string.
char const * GetKicadPluginClass(void)
GET_PLUGIN_CLASS m_getPluginClass
Definition pluginldr.h:137
GET_CLASS_VERSION m_getClassVersion
Definition pluginldr.h:138
GET_VERSION m_getVersion
Definition pluginldr.h:141
std::string m_pluginInfo
Definition pluginldr.h:143
virtual void Close(void)=0
Clean up and closes/unloads the plugin.
virtual bool Open(const wxString &aFullFileName)=0
Open a plugin of the given class, performs version compatibility checks, and links all required funct...
bool CheckClassVersion(unsigned char Major, unsigned char Minor, unsigned char Patch, unsigned char Revision)
GET_PLUGIN_NAME m_getPluginName
Definition pluginldr.h:140
void GetPluginInfo(std::string &aPluginInfo)
bool open(const wxString &aFullFileName, const char *aPluginClass)
Open a plugin of the specified class and links the extensions required by kicad_plugin.
Definition pluginldr.cpp:59
bool GetClassVersion(unsigned char *Major, unsigned char *Minor, unsigned char *Patch, unsigned char *Revision)
wxDynamicLibrary m_PluginLoader
Definition pluginldr.h:133
bool GetVersion(unsigned char *Major, unsigned char *Minor, unsigned char *Patch, unsigned char *Revision)
const char * GetKicadPluginName(void)
std::string m_error
Definition pluginldr.h:130
virtual ~KICAD_PLUGIN_LDR()
Definition pluginldr.cpp:52
void close(void)
Nullify internal pointers in preparation for closing the plugin.
wxString m_fileName
Definition pluginldr.h:142
bool reopen(void)
Reopen a plugin.
const wxChar *const tracePluginLoader
Flag to enable plugin loader trace output.
Definition pluginldr.cpp:36
defines the most basic functions which all kicad plugin loaders require.
void(* GET_VERSION)(unsigned char *, unsigned char *, unsigned char *, unsigned char *)
Definition pluginldr.h:55
void(* GET_CLASS_VERSION)(unsigned char *, unsigned char *, unsigned char *, unsigned char *)
Definition pluginldr.h:47
bool(* CHECK_CLASS_VERSION)(unsigned char, unsigned char, unsigned char, unsigned char)
Definition pluginldr.h:50
char const *(* GET_PLUGIN_CLASS)(void)
Definition pluginldr.h:45
const char *(* GET_PLUGIN_NAME)(void)
Definition pluginldr.h:53
#define LINK_ITEM(funcPtr, funcType, funcName)
Definition pluginldr.h:41