32#include <unordered_map>
40#if defined(__linux__) && !defined(__ANDROID__)
53#include <wx/hashset.h>
54#include <wx/filename.h>
56#include <wx/tokenzr.h>
59#include "plugin_loader.h"
61#include "base_platform.h"
62#include "config_vars.h"
63#include "ocpn_utils.h"
65#include "observable_confvar.h"
66#include "observable_evtvar.h"
67#include "plugin_blacklist.h"
68#include "plugin_cache.h"
69#include "plugin_handler.h"
70#include "plugin_paths.h"
75#include "androidUTIL.h"
80extern wxWindow* gFrame;
83const char*
const LINUX_LOAD_PATH =
"~/.local/lib:/usr/local/lib:/usr/lib";
84const char*
const FLATPAK_LOAD_PATH =
"~/.var/app/org.opencpn.OpenCPN/lib";
86static const std::vector<std::string> SYSTEM_PLUGINS = {
87 "chartdownloader",
"wmm",
"dashboard",
"grib"};
90PlugInContainer::PlugInContainer() {
94 m_bToolboxPanel =
false;
96 m_pluginStatus = PluginStatus::Unknown;
101 if (m_ManagedMetadata.version.size()) {
111 plugin_117->GetPlugInVersionMajor(),
112 plugin_117->GetPlugInVersionMinor(),
113 plugin_117->GetPlugInVersionPatch(), plugin_117->GetPlugInVersionPost(),
114 plugin_117->GetPlugInVersionPre(), plugin_117->GetPlugInVersionBuild());
117 m_pplugin->GetPlugInVersionMinor(),
137static void setLoadPath() {
140 auto const osSystemId = wxPlatformInfo::Get().GetOperatingSystemId();
142 if (osSystemId & wxOS_UNIX_LINUX) {
143 string path = ocpn::join(dirs,
':');
145 if (wxGetEnv(
"LD_LIBRARY_PATH", &envPath)) {
146 path = path +
":" + envPath.ToStdString();
148 wxLogMessage(
"Using LD_LIBRARY_PATH: %s", path.c_str());
149 wxSetEnv(
"LD_LIBRARY_PATH", path.c_str());
150 }
else if (osSystemId & wxOS_WINDOWS) {
152 string path = ocpn::join(dirs,
';');
154 if (wxGetEnv(
"PATH", &envPath)) {
155 path = path +
";" + envPath.ToStdString();
157 wxLogMessage(
"Using PATH: %s", path);
158 wxSetEnv(
"PATH", path);
159 }
else if (osSystemId & wxOS_MAC) {
160 string path = ocpn::join(dirs,
':');
162 if (wxGetEnv(
"DYLD_LIBRARY_PATH", &envPath)) {
163 path = path +
":" + envPath.ToStdString();
165 wxLogMessage(
"Using DYLD_LIBRARY_PATH: %s", path.c_str());
166 wxSetEnv(
"DYLD_LIBRARY_PATH", path.c_str());
168 wxString os_name = wxPlatformInfo::Get().GetPortIdName();
169 if (os_name.Contains(
"wxQT")) {
170 wxLogMessage(
"setLoadPath() using Android library path");
172 wxLogWarning(
"SetLoadPath: Unsupported platform.");
174 if (osSystemId & wxOS_MAC || osSystemId & wxOS_UNIX_LINUX) {
176 string path = ocpn::join(dirs,
':');
178 wxGetEnv(
"PATH", &envPath);
179 path = path +
":" + envPath.ToStdString();
180 wxLogMessage(
"Using PATH: %s", path);
181 wxSetEnv(
"PATH", path);
192PluginLoader::PluginLoader()
193 : m_blacklist(blacklist_factory()), m_default_plugin_icon(0) {}
195bool PluginLoader::IsPlugInAvailable(wxString commonName) {
196 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
198 if (pic && pic->m_bEnabled && (pic->m_common_name == commonName))
205 if (pic->m_cap_flag & WANTS_LATE_INIT) {
206 wxString msg(
"PlugInManager: Calling LateInit PlugIn: ");
207 msg += pic->m_plugin_file;
212 if (ppi) ppi->LateInit();
216const wxBitmap* PluginLoader::GetPluginDefaultIcon() {
217 if (!m_default_plugin_icon)
218 m_default_plugin_icon =
new wxBitmap(32, 32);
219 return m_default_plugin_icon;
222void PluginLoader::SetPluginDefaultIcon(
const wxBitmap* bitmap) {
223 delete m_default_plugin_icon;
224 m_default_plugin_icon = bitmap;
228bool PluginLoader::LoadAllPlugIns(
bool load_enabled) {
231 static const wxString sep = wxFileName::GetPathSeparator();
233 wxLogMessage(
"PlugInManager: loading plugins from %s", ocpn::join(dirs,
';'));
235 bool any_dir_loaded =
false;
236 for (
auto dir : dirs) {
238 wxLogMessage(
"Loading plugins from dir: %s", wxdir.mb_str().data());
239 if (LoadPlugInDirectory(wxdir, load_enabled))
240 any_dir_loaded =
true;
246 if (!load_enabled) UpdateManagedPlugins();
249 evt_update_chart_types.
Notify();
250 evt_plugin_loadall_finalize.
Notify();
252 return any_dir_loaded;
255bool PluginLoader::LoadPluginCandidate(wxString file_name,
bool load_enabled) {
257 wxString plugin_file = wxFileName(file_name).GetFullName();
258 wxLogMessage(
"Checking plugin candidate: %s", file_name.mb_str().data());
259 wxDateTime plugin_modification =
260 wxFileName(file_name).GetModificationTime();
268 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
272 if (pic_test->m_plugin_filename == plugin_file) {
275 if (pic_test->m_plugin_file == file_name) {
276 if (pic_test->m_plugin_modification != plugin_modification) {
278 plugin_array.Remove(pic_test);
281 DeactivatePlugIn(pic_test);
282 pic_test->m_destroy_fn(pic_test->m_pplugin);
287 loaded_pic = pic_test;
292 loaded_pic = pic_test;
298 if (loaded)
return true;
302 const auto path = std::string(
"/PlugIns/") + plugin_file.ToStdString();
306 if (load_enabled && !enabled.Get(
true)) {
307 wxLogMessage(
"Skipping not enabled candidate.");
311 bool b_compat = CheckPluginCompatibility(file_name);
314 auto msg = std::string(_(
"Incompatible plugin detected: ")
315 + file_name.ToStdString());
316 wxLogMessage(msg.c_str());
317 if (m_blacklist->mark_unloadable(file_name.ToStdString())) {
318 evt_incompatible_plugin.
Notify(msg);
323 if (b_compat) pic = LoadPlugIn(file_name);
325 wxLog::FlushActive();
328 if (pic->m_pplugin) {
329 plugin_array.Add(pic);
333 pic->m_common_name = pic->m_pplugin->GetCommonName();
334 pic->m_plugin_filename = plugin_file;
335 pic->m_plugin_modification = plugin_modification;
336 pic->m_bEnabled = enabled.Get(
false);
338 if (safe_mode::get_mode()) {
339 pic->m_bEnabled =
false;
344 if (pic->m_bEnabled) {
345 pic->m_cap_flag = pic->m_pplugin->Init();
346 pic->m_bInitState =
true;
347 evt_load_plugin.
Notify(pic);
350 wxLog::FlushActive();
352 std::string found_version;
353 for (
auto p : PluginHandler::getInstance()->getInstalled()) {
354 if (p.name == pic->m_common_name.Lower()) {
355 found_version = p.readonly ?
"" : p.version;
359 pic->m_version_str = found_version;
360 pic->m_short_description = pic->m_pplugin->GetShortDescription();
361 pic->m_long_description = pic->m_pplugin->GetLongDescription();
362 pic->m_version_major = pic->m_pplugin->GetPlugInVersionMajor();
363 pic->m_version_minor = pic->m_pplugin->GetPlugInVersionMinor();
366 wxBitmap* pbm =
new wxBitmap(pic->m_bitmap->GetSubBitmap(wxRect(
367 0, 0, pic->m_bitmap->GetWidth(), pic->m_bitmap->GetHeight())));
370 if (!pic->m_bEnabled && pic->m_destroy_fn) {
371 wxBitmap* pbm =
new wxBitmap(pic->m_bitmap->GetSubBitmap(wxRect(
372 0, 0, pic->m_bitmap->GetWidth(), pic->m_bitmap->GetHeight())));
374 pic->m_destroy_fn(pic->m_pplugin);
375 pic->m_destroy_fn = NULL;
376 pic->m_pplugin = NULL;
377 pic->m_bInitState =
false;
378 if (pic->m_library.IsLoaded()) pic->m_library.Unload();
385 " PlugInManager: Unloading invalid PlugIn, API version %d ",
389 pic->m_destroy_fn(pic->m_pplugin);
398bool PluginLoader::LoadPlugInDirectory(
const wxString& plugin_dir,
400 evt_load_directory.
Notify();
401 m_plugin_location = plugin_dir;
403 wxString msg(
"PlugInManager searching for PlugIns in location ");
404 msg += m_plugin_location;
408 wxString pispec =
"*_pi.dll";
409#elif defined(__WXOSX__)
410 wxString pispec =
"*_pi.dylib";
412 wxString pispec =
"*_pi.so";
415 if (!::wxDirExists(m_plugin_location)) {
416 msg = m_plugin_location;
417 msg.Prepend(
" Directory ");
418 msg.Append(
" does not exist.");
423 if (!g_BasePlatform->isPlatformCapable(PLATFORM_CAP_PLUGINS))
return false;
425 wxArrayString file_list;
427 int get_flags = wxDIR_FILES | wxDIR_DIRS;
430 get_flags = wxDIR_FILES;
435 get_flags = wxDIR_FILES;
441 wxDir::GetAllFiles(m_plugin_location, &file_list, pispec, get_flags);
443 wxLogMessage(
"Found %d candidates", (
int)file_list.GetCount());
444 for (
unsigned int i = 0; i < file_list.GetCount(); i++) {
445 wxLog::FlushActive();
447 wxString file_name = file_list[i];
450 LoadPluginCandidate(file_name, load_enabled);
457 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
459 for (
unsigned int j = i + 1; j < plugin_array.GetCount(); j++) {
462 if (pic->m_common_name == pict->m_common_name) {
463 if (pic->m_plugin_file.IsEmpty())
464 plugin_array.Item(i)->m_pluginStatus =
465 PluginStatus::PendingListRemoval;
467 plugin_array.Item(j)->m_pluginStatus =
468 PluginStatus::PendingListRemoval;
475 while ((i >= 0) && (i < plugin_array.GetCount())) {
477 if (pict->m_pluginStatus == PluginStatus::PendingListRemoval) {
478 plugin_array.RemoveAt(i);
487bool PluginLoader::UpdatePlugIns() {
490 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
495 if (pic->m_pplugin) {
498 pic->m_pplugin = NULL;
499 pic->m_bInitState =
false;
504 if (!pic->m_pplugin) {
505 if (pic->m_bEnabled) {
506 PluginStatus stat = pic->m_pluginStatus;
509 pic->m_pluginStatus = stat;
510 pic->m_bEnabled =
true;
516 if (pic->m_bEnabled && !pic->m_bInitState && pic->m_pplugin) {
517 wxString msg(
"PlugInManager: Initializing PlugIn: ");
518 msg += pic->m_plugin_file;
521 pic->m_cap_flag = pic->m_pplugin->Init();
522 pic->m_pplugin->SetDefaults();
523 pic->m_bInitState =
true;
524 ProcessLateInit(pic);
525 pic->m_short_description = pic->m_pplugin->GetShortDescription();
526 pic->m_long_description = pic->m_pplugin->GetLongDescription();
527 pic->m_version_major = pic->m_pplugin->GetPlugInVersionMajor();
528 pic->m_version_minor = pic->m_pplugin->GetPlugInVersionMinor();
531 }
else if (!pic->m_bEnabled && pic->m_bInitState) {
533 wxBitmap* pbm =
new wxBitmap(pic->m_bitmap->GetSubBitmap(
534 wxRect(0, 0, pic->m_bitmap->GetWidth(), pic->m_bitmap->GetHeight())));
537 bret = DeactivatePlugIn(pic);
538 if (pic->m_pplugin) pic->m_destroy_fn(pic->m_pplugin);
539 if (pic->m_library.IsLoaded()) pic->m_library.Unload();
540 pic->m_pplugin = NULL;
541 pic->m_bInitState =
false;
544 evt_update_chart_types.
Notify();
550 if (!pic)
return false;
551 if (pic->m_bInitState) {
552 wxString msg(
"PlugInManager: Deactivating PlugIn: ");
553 wxLogMessage(msg + pic->m_plugin_file);
557 if ((pic->m_cap_flag & INSTALLS_PLUGIN_CHART) ||
558 (pic->m_cap_flag & INSTALLS_PLUGIN_CHART_GL)) {
559 ChartData->PurgeCachePlugins();
563 pic->m_bInitState =
false;
564 pic->m_pplugin->DeInit();
583static std::vector<PluginMetadata> getCompatiblePlugins() {
585 struct metadata_compare {
588 return lhs.key() < rhs.key();
592 std::vector<PluginMetadata> returnArray;
594 std::set<PluginMetadata, metadata_compare> unique_plugins;
595 for (
auto plugin : PluginHandler::getInstance()->getAvailable()) {
596 unique_plugins.insert(plugin);
598 for (
auto plugin : unique_plugins) {
600 returnArray.push_back(plugin);
607 if (ix >= plugin_array.GetCount()) {
608 wxLogWarning(
"Attempt to remove non-existing plugin %d", ix);
612 if (!DeactivatePlugIn(pic)) {
615 if (pic->m_pplugin) {
616 pic->m_destroy_fn(pic->m_pplugin);
620 plugin_array.RemoveAt(ix);
624void PluginLoader::UpdateManagedPlugins() {
627 for (
size_t i = 0; i < plugin_array.GetCount(); i++) {
628 pict = plugin_array.Item(i);
629 plugin_array.Item(i)->m_pluginStatus = PluginStatus::Unmanaged;
633 std::find(SYSTEM_PLUGINS.begin(), SYSTEM_PLUGINS.end(),
634 plugin_array.Item(i)->m_common_name.Lower().ToStdString());
635 if (r != SYSTEM_PLUGINS.end())
636 plugin_array.Item(i)->m_pluginStatus = PluginStatus::System;
639 std::vector<PluginMetadata> available = getCompatiblePlugins();
645 for (
size_t i = 0; i < plugin_array.GetCount(); i++) {
646 pict = plugin_array.Item(i);
647 if (pict->m_ManagedMetadata.name
650 for (
auto plugin : available) {
651 if (pict->m_common_name.IsSameAs(wxString(plugin.name.c_str()))) {
657 if (!pict->m_pplugin) {
658 plugin_array.Item(i)->m_pluginStatus =
659 PluginStatus::PendingListRemoval;
667 while ((i >= 0) && (i < plugin_array.GetCount())) {
668 pict = plugin_array.Item(i);
669 if (pict->m_pluginStatus == PluginStatus::PendingListRemoval) {
670 plugin_array.RemoveAt(i);
676 for (
size_t i = 0; i < plugin_array.GetCount(); i++) {
677 pict = plugin_array.Item(i);
682 for (
auto plugin : available) {
686 for (
size_t i = 0; i < plugin_array.GetCount(); i++) {
687 pic = plugin_array.Item(i);
688 if (plugin_array.Item(i)->m_common_name.IsSameAs(
689 wxString(plugin.name.c_str()))) {
698 new_pic->m_common_name = wxString(plugin.name.c_str());
699 new_pic->m_pluginStatus = PluginStatus::ManagedInstallAvailable;
700 new_pic->m_ManagedMetadata = plugin;
701 new_pic->m_version_major = 0;
702 new_pic->m_version_minor = 0;
707 if (safe_mode::get_mode()) {
708 std::string installed;
712 if (path !=
"" && wxFileName::IsFileReadable(path)) {
713 std::ifstream stream;
714 stream.open(path, std::ifstream::in);
718 if (!installed.empty())
719 new_pic->m_pluginStatus =
720 PluginStatus::ManagedInstalledCurrentVersion;
722 new_pic->m_pluginStatus = PluginStatus::Unknown;
725 plugin_array.Add(new_pic);
734 std::string installed;
736 if (path !=
"" && wxFileName::IsFileReadable(path)) {
737 std::ifstream stream;
738 stream.open(path, std::ifstream::in);
741 pic->m_InstalledManagedVersion = installed;
746 if (installedVersion < metaVersion)
747 pic->m_pluginStatus = PluginStatus::ManagedInstalledUpdateAvailable;
748 else if (installedVersion == metaVersion)
749 pic->m_pluginStatus = PluginStatus::ManagedInstalledCurrentVersion;
750 else if (installedVersion > metaVersion)
751 pic->m_pluginStatus =
752 PluginStatus::ManagedInstalledDowngradeAvailable;
754 pic->m_ManagedMetadata = plugin;
763 if (pic->m_api_version) {
764 pic->m_pluginStatus = PluginStatus::LegacyUpdateAvailable;
765 pic->m_ManagedMetadata = plugin;
769 pic->m_pluginStatus = PluginStatus::ManagedInstallAvailable;
778 std::map<std::string, PlugInContainer*> sortmap;
779 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
781 if (pic->m_pluginStatus == PluginStatus::ManagedInstallAvailable) {
782 plugin_array.Remove(pic);
785 std::string name = pic->m_ManagedMetadata.name;
786 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
794 for (std::map<std::string, PlugInContainer*>::iterator i = sortmap.begin();
795 i != sortmap.end(); i++) {
797 plugin_array.Insert(pic, 0);
799 evt_pluglist_change.
Notify();
802bool PluginLoader::UnLoadAllPlugIns() {
804 while (plugin_array.GetCount()) {
812bool PluginLoader::DeactivateAllPlugIns() {
813 for (
unsigned int i = 0; i < plugin_array.GetCount(); i++) {
815 if (pic && pic->m_bEnabled && pic->m_bInitState) DeactivatePlugIn(pic);
822DWORD Rva2Offset(DWORD rva, PIMAGE_SECTION_HEADER psh, PIMAGE_NT_HEADERS pnt) {
824 PIMAGE_SECTION_HEADER pSeh;
829 for (i = 0; i < pnt->FileHeader.NumberOfSections; i++) {
830 if (rva >= pSeh->VirtualAddress &&
831 rva < pSeh->VirtualAddress + pSeh->Misc.VirtualSize) {
836 return (rva - pSeh->VirtualAddress + pSeh->PointerToRawData);
842 WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual, DependencySet);
843 WX_DECLARE_HASH_MAP(wxString, wxString, wxStringHash, wxStringEqual,
847 DependencyMap dependencies;
851bool ReadModuleInfoFromELF(
const wxString& file,
852 const ModuleInfo::DependencySet& dependencies,
854 static bool b_libelf_initialized =
false;
855 static bool b_libelf_usable =
false;
857 if (b_libelf_usable) {
859 }
else if (b_libelf_initialized) {
861 }
else if (elf_version(EV_CURRENT) == EV_NONE) {
862 b_libelf_initialized =
true;
863 b_libelf_usable =
false;
864 wxLogError(
"LibELF is outdated.");
867 b_libelf_initialized =
true;
868 b_libelf_usable =
true;
872 Elf* elf_handle = NULL;
873 GElf_Ehdr elf_file_header;
874 Elf_Scn* elf_section_handle = NULL;
876 file_handle = open(file, O_RDONLY);
877 if (file_handle == -1) {
878 wxLogError(
"Could not open file \"%s\" for reading: %s", file,
880 goto FailureEpilogue;
883 elf_handle = elf_begin(file_handle, ELF_C_READ, NULL);
884 if (elf_handle == NULL) {
885 wxLogError(
"Could not get ELF structures from \"%s\".", file);
886 goto FailureEpilogue;
889 if (gelf_getehdr(elf_handle, &elf_file_header) != &elf_file_header) {
890 wxLogError(
"Could not get ELF file header from \"%s\".", file);
891 goto FailureEpilogue;
894 switch (elf_file_header.e_type) {
899 wxLogError(wxString::Format(
900 "Module \"%s\" is not an executable or shared library.", file));
901 goto FailureEpilogue;
905 (
static_cast<uint64_t
>(elf_file_header.e_ident[EI_CLASS])
907 (
static_cast<uint64_t
>(elf_file_header.e_ident[EI_DATA])
909 (
static_cast<uint64_t
>(elf_file_header.e_ident[EI_OSABI])
911 (
static_cast<uint64_t
>(elf_file_header.e_ident[EI_ABIVERSION])
913 (
static_cast<uint64_t
>(elf_file_header.e_machine)
917 while ((elf_section_handle = elf_nextscn(elf_handle, elf_section_handle)) !=
919 GElf_Shdr elf_section_header;
920 Elf_Data* elf_section_data = NULL;
921 size_t elf_section_entry_count = 0;
923 if (gelf_getshdr(elf_section_handle, &elf_section_header) !=
924 &elf_section_header) {
925 wxLogError(
"Could not get ELF section header from \"%s\".", file);
926 goto FailureEpilogue;
927 }
else if (elf_section_header.sh_type != SHT_DYNAMIC) {
931 elf_section_data = elf_getdata(elf_section_handle, NULL);
932 if (elf_section_data == NULL) {
933 wxLogError(
"Could not get ELF section data from \"%s\".", file);
934 goto FailureEpilogue;
937 if ((elf_section_data->d_size == 0) ||
938 (elf_section_header.sh_entsize == 0)) {
939 wxLogError(
"Got malformed ELF section metadata from \"%s\".", file);
940 goto FailureEpilogue;
943 elf_section_entry_count =
944 elf_section_data->d_size / elf_section_header.sh_entsize;
945 for (
size_t elf_section_entry_index = 0;
946 elf_section_entry_index < elf_section_entry_count;
947 ++elf_section_entry_index) {
948 GElf_Dyn elf_dynamic_entry;
949 const char* elf_dynamic_entry_name = NULL;
950 if (gelf_getdyn(elf_section_data, elf_section_entry_index,
951 &elf_dynamic_entry) != &elf_dynamic_entry) {
952 wxLogError(
"Could not get ELF dynamic_section entry from \"%s\".",
954 goto FailureEpilogue;
955 }
else if (elf_dynamic_entry.d_tag != DT_NEEDED) {
958 elf_dynamic_entry_name = elf_strptr(
959 elf_handle, elf_section_header.sh_link, elf_dynamic_entry.d_un.d_val);
960 if (elf_dynamic_entry_name == NULL) {
961 wxLogError(wxString::Format(
"Could not get %s %s from \"%s\".",
"ELF",
962 "string entry", file));
963 goto FailureEpilogue;
965 wxString name_full(elf_dynamic_entry_name);
966 wxString name_part(elf_dynamic_entry_name,
967 strcspn(elf_dynamic_entry_name,
"-."));
968 if (dependencies.find(name_part) != dependencies.end()) {
969 info.dependencies.insert(
970 ModuleInfo::DependencyMap::value_type(name_part, name_full));
975 goto SuccessEpilogue;
983 if (elf_handle != NULL) elf_end(elf_handle);
984 if (file_handle >= 0) close(file_handle);
989bool PluginLoader::CheckPluginCompatibility(wxString plugin_file) {
990 bool b_compat =
true;
994 sprintf(strver,
"%i%i", wxMAJOR_VERSION, wxMINOR_VERSION);
995 LPCWSTR fNmae = plugin_file.wc_str();
996 HANDLE handle = CreateFile(fNmae, GENERIC_READ, 0, 0, OPEN_EXISTING,
997 FILE_ATTRIBUTE_NORMAL, 0);
998 DWORD byteread, size = GetFileSize(handle, NULL);
999 PVOID virtualpointer = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
1000 ReadFile(handle, virtualpointer, size, &byteread, NULL);
1001 CloseHandle(handle);
1003 PIMAGE_NT_HEADERS ntheaders =
1004 (PIMAGE_NT_HEADERS)(PCHAR(virtualpointer) +
1005 PIMAGE_DOS_HEADER(virtualpointer)->e_lfanew);
1006 PIMAGE_SECTION_HEADER pSech =
1007 IMAGE_FIRST_SECTION(ntheaders);
1008 PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
1009 if (ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1014 (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)virtualpointer +
1016 ntheaders->OptionalHeader
1018 [IMAGE_DIRECTORY_ENTRY_IMPORT]
1024 while (pImportDescriptor->Name != 0) {
1027 (PCHAR)((DWORD_PTR)virtualpointer +
1028 Rva2Offset(pImportDescriptor->Name, pSech, ntheaders));
1029 if (strstr(libname[i],
"wx") != NULL) {
1030 if (strstr(libname[i], strver) == NULL) b_compat =
false;
1033 pImportDescriptor++;
1038 wxString::Format(
"No Import Table! in %s", plugin_file.c_str()));
1040 if (virtualpointer) VirtualFree(virtualpointer, size, MEM_DECOMMIT);
1042#if defined(__WXGTK__) || defined(__WXQT__)
1043#if defined(USE_LIBELF)
1045 static bool b_own_info_queried =
false;
1046 static bool b_own_info_usable =
false;
1048 static ModuleInfo::DependencySet dependencies;
1050 if (!b_own_info_queried) {
1051 dependencies.insert(
"libwx_baseu");
1052 const wxApp& app = *wxTheApp;
1053 if (app.argc && !app.argv[0].IsEmpty()) {
1054 wxString app_path(app.argv[0]);
1056 ReadModuleInfoFromELF(app_path, dependencies, own_info);
1058 wxLogError(
"Cannot get own executable path.");
1060 b_own_info_queried =
true;
1063 if (b_own_info_usable) {
1064 bool b_pi_info_usable =
false;
1067 ReadModuleInfoFromELF(plugin_file, dependencies, pi_info);
1068 if (b_pi_info_usable) {
1069 b_compat = (pi_info.type_magic == own_info.type_magic);
1072 if ((pi_info.type_magic ^ own_info.type_magic) == 0x00030000)
1076 pi_info.dependencies.clear();
1078 wxString::Format(
" Plugin \"%s\" is of another binary "
1079 "flavor than the main module.",
1081 wxLogDebug(
"host magic: %.8x, plugin magic: %.8x", own_info.type_magic,
1082 pi_info.type_magic);
1084 for (ModuleInfo::DependencyMap::const_iterator own_dependency =
1085 own_info.dependencies.begin();
1086 own_dependency != own_info.dependencies.end(); ++own_dependency) {
1087 ModuleInfo::DependencyMap::const_iterator pi_dependency =
1088 pi_info.dependencies.find(own_dependency->first);
1089 if ((pi_dependency != pi_info.dependencies.end()) &&
1090 (pi_dependency->second != own_dependency->second)) {
1093 " Plugin \"%s\" depends on library \"%s\", but the main "
1094 "module was built for \"%s\".",
1095 plugin_file, pi_dependency->second, own_dependency->second);
1102 wxString::Format(
" Plugin \"%s\" could not be reliably "
1103 "checked for compatibility.",
1111 wxLogMessage(
"Plugin is compatible by elf library scan: %s",
1112 b_compat ?
"true" :
"false");
1127 FILE* f = fopen(plugin_file,
"r");
1131#
if defined(__WXGTK3__)
1132 "libwx_gtk3u_core-%i.%i"
1133#elif defined(__WXGTK20__)
1134 "libwx_gtk2u_core-%i.%i"
1135#elif defined(__WXQT__)
1136 "libwx_qtu_core-%i.%i"
1138#error undefined plugin platform
1141 wxMAJOR_VERSION, wxMINOR_VERSION);
1144 int pos = 0, len = strlen(strver), c;
1145 while ((c = fgetc(f)) != EOF) {
1146 if (c == strver[pos]) {
1157 wxLogMessage(
"Plugin is compatible: %s", b_compat ?
"true" :
"false");
1163 if (!LoadPlugIn(plugin_file, pic)) {
1172 wxLogMessage(wxString(
"PlugInManager: Loading PlugIn: ") + plugin_file);
1175 auto sts = m_blacklist->get_status(pic->m_common_name.ToStdString(),
1176 pic->m_version_major,
1177 pic->m_version_minor);
1178 if (sts != plug_status::unblocked) {
1179 wxLogDebug(
"Refusing to load blacklisted plugin: %s",
1180 pic->m_common_name.ToStdString().c_str());
1183 auto data = m_blacklist->get_library_data(plugin_file.ToStdString());
1184 if (data.name !=
"") {
1185 wxLogDebug(
"Refusing to load blacklisted library: %s",
1186 plugin_file.ToStdString().c_str());
1189 pic->m_plugin_file = plugin_file;
1190 pic->m_pluginStatus =
1191 PluginStatus::Unmanaged;
1195 if (pic->m_library.IsLoaded()) pic->m_library.Unload();
1197 if (!wxIsReadable(plugin_file)) {
1198 evt_unreadable_plugin.
Notify(plugin_file.ToStdString());
1202 pic->m_library.Load(plugin_file);
1204 if (!pic->m_library.IsLoaded()) {
1208 wxFileName fn(plugin_file);
1209 std::string name = fn.GetName().ToStdString();
1210 wxString msg(wxString::Format(
"%s:\n%s\n\n",
1211 _(
"Incompatible plugin detected"),
1213 auto found = m_blacklist->get_library_data(name);
1214 if (found.name !=
"") {
1215 auto msg1 = wxString::Format(_(
"PlugIn [ %s ] version %i.%i"),
1216 found.name.c_str(), found.major,
1219 msg += _(
" is incompatible with this version of OpenCPN.");
1222 msg = wxString(
" PlugInManager: Cannot load library:") + plugin_file;
1224 if (m_blacklist->mark_unloadable(plugin_file.ToStdString()))
1225 evt_incompatible_plugin.
Notify(msg.ToStdString());
1226 wxLogMessage(wxString(
" PlugInManager: Cannot load library: ")
1232 const char*
const FIX_LOADING =
1233 _(
"\n Install/uninstall plugin or remove file to mute message");
1234 create_t* create_plugin = (create_t*)pic->m_library.GetSymbol(
"create_pi");
1235 if (NULL == create_plugin) {
1236 std::string msg(_(
" PlugInManager: Cannot load symbol create_pi: "));
1238 wxLogMessage(msg.c_str());
1239 if (m_blacklist->mark_unloadable(plugin_file.ToStdString()))
1240 evt_incompatible_plugin.
Notify(msg + FIX_LOADING);
1244 destroy_t* destroy_plugin =
1245 (destroy_t*)pic->m_library.GetSymbol(
"destroy_pi");
1246 pic->m_destroy_fn = destroy_plugin;
1247 if (NULL == destroy_plugin) {
1248 std::string msg(_(
" PlugInManager: Cannot load symbol destroy_pi: "));
1250 wxLogMessage(msg.c_str());
1251 if (m_blacklist->mark_unloadable(plugin_file.ToStdString()))
1252 evt_incompatible_plugin.
Notify(msg + FIX_LOADING);
1259 int api_major = plug_in->GetAPIVersionMajor();
1260 int api_minor = plug_in->GetAPIVersionMinor();
1261 int api_ver = (api_major * 100) + api_minor;
1262 pic->m_api_version = api_ver;
1264 int pi_major = plug_in->GetPlugInVersionMajor();
1265 int pi_minor = plug_in->GetPlugInVersionMinor();
1268 wxString pi_name = plug_in->GetCommonName();
1270 wxLogDebug(
"blacklist: Get status for %s %d %d",
1271 pi_name.ToStdString().c_str(), pi_major, pi_minor);
1272 const auto status = m_blacklist->get_status(pi_name.ToStdString(),
1273 pi_major, pi_minor);
1274 if (status != plug_status::unblocked) {
1275 wxLogDebug(
"Ignoring blacklisted plugin.");
1276 if (status != plug_status::unloadable) {
1277 plug_data data(pi_name.ToStdString(), pi_major, pi_minor);
1278 auto msg = m_blacklist->get_message(status, data);
1279 evt_incompatible_plugin.
Notify(msg);
1338 p->GetPlugInVersionPost(), p->GetPlugInVersionPre(),
1339 p->GetPlugInVersionBuild());
1348 p->GetPlugInVersionPost(), p->GetPlugInVersionPre(),
1349 p->GetPlugInVersionBuild());
1357 std::stringstream ss;
1358 if (!pic->m_pplugin) {
1359 ss << _(
"Incompatible plugin detected: ") << plugin_file <<
"\n";
1360 ss << _(
" API Version detected: ");
1361 ss << api_major <<
"." << api_minor <<
"\n";
1362 ss << _(
" PlugIn Version detected: ") << pi_ver <<
"\n";
1363 INFO_LOG << ss.str();
1364 if (m_blacklist->mark_unloadable(pi_name.ToStdString(), pi_ver.major,
1367 evt_incompatible_plugin.
Notify(ss.str());
Wrapper for configuration variables which lives in a wxBaseConfig object.
const void Notify()
Notify all listeners, no data supplied.
SemanticVersion GetVersion()
Return version from plugin API.
static std::string fileListPath(std::string name)
Return path to installation manifest for given plugin.
static std::string versionPath(std::string name)
Return path to file containing version for given plugin.
static bool isCompatible(const PluginMetadata &metadata, const char *os=PKG_TARGET, const char *os_version=PKG_TARGET_VERSION)
Return true if given plugin is loadable on given os/version.
PluginLoader is a backend module without any direct GUI functionality.
bool UnLoadPlugIn(size_t ix)
Unload, delete and remove item ix in GetPlugInArray().
EventVar evt_deactivate_plugin
Receives a malloc'ed copy of a PlugInContainer owned by listener.
std::vector< std::string > Libdirs()
List of directories from which we load plugins.
std::vector< std::string > Bindirs()
'List of directories for plugin binary helpers.
static PluginPaths * getInstance()
Return the singleton instance.
virtual wxBitmap * GetPlugInBitmap()
FIXME static wxBitmap* LoadSVG(const wxString filename, unsigned int width, ...
Versions uses a modified semantic versioning scheme: major.minor.revision.post-tag+build.
static SemanticVersion parse(std::string s)
Parse a version string, sets major == -1 on errors.