From f9118dd13c637a4054c101e685c9030115f790c8 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Sun, 6 Mar 2022 02:08:04 +0100 Subject: [PATCH] Use plugin list's plugin compatibility info for loading plugins A new ability for checking plugins' compatibility with running Notepad++ has been added in Plugin List & Plugin Admin (https://github.com/notepad-plus-plus/notepad-plus-plus/commit/a06b404708e73ed25bec3c2e9ed132d1a1e5c2ef). This PR extends this ability by using Plugin Admin's plugin list to filter plugins to load - if any plugin to load with **the same folder name**, **the same version** (as in the plugin list) and it's **not compatible** with the running Notepad++ version found while loading plugins, it will be skipped for being loaded. Fix #11353, close #11350 --- PowerEditor/src/MISC/Common/Common.cpp | 175 ++++++++++ PowerEditor/src/MISC/Common/Common.h | 55 +++ .../MISC/PluginsManager/PluginsManager.cpp | 63 +++- .../src/MISC/PluginsManager/PluginsManager.h | 3 +- PowerEditor/src/Notepad_plus.cpp | 16 +- PowerEditor/src/NppCommands.cpp | 2 +- PowerEditor/src/Parameters.h | 15 - .../WinControls/PluginsAdmin/pluginsAdmin.cpp | 328 ++++-------------- .../WinControls/PluginsAdmin/pluginsAdmin.h | 67 +--- 9 files changed, 381 insertions(+), 343 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 46dcf59e9..6f3a09da0 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -1517,3 +1517,178 @@ HFONT createFont(const TCHAR* fontName, int fontSize, bool isBold, HWND hDestPar return newFont; } + +Version::Version(const generic_string& versionStr) +{ + try { + auto ss = tokenizeString(versionStr, '.'); + + if (ss.size() > 4) + throw std::wstring(TEXT("Version parts are more than 4. The string to parse is not a valid version format. Let's make it default value in catch block.")); + + int i = 0; + std::vector v = { &_major, &_minor, &_patch, &_build }; + for (const auto& s : ss) + { + if (!isNumber(s)) + { + throw std::wstring(TEXT("One of version character is not number. The string to parse is not a valid version format. Let's make it default value in catch block.")); + } + *(v[i]) = std::stoi(s); + + ++i; + } + } +#ifdef DEBUG + catch (const std::wstring& s) + { + _major = 0; + _minor = 0; + _patch = 0; + _build = 0; + + throw s; + } +#endif + catch (...) + { + _major = 0; + _minor = 0; + _patch = 0; + _build = 0; +#ifdef DEBUG + throw std::wstring(TEXT("Unknown exception from \"Version::Version(const generic_string& versionStr)\"")); +#endif + } +} + + +void Version::setVersionFrom(const generic_string& filePath) +{ + if (!filePath.empty() && ::PathFileExists(filePath.c_str())) + { + DWORD uselessArg = 0; // this variable is for passing the ignored argument to the functions + DWORD bufferSize = ::GetFileVersionInfoSize(filePath.c_str(), &uselessArg); + + if (bufferSize <= 0) + return; + + unsigned char* buffer = new unsigned char[bufferSize]; + ::GetFileVersionInfo(filePath.c_str(), uselessArg, bufferSize, buffer); + + VS_FIXEDFILEINFO* lpFileInfo = nullptr; + UINT cbFileInfo = 0; + VerQueryValue(buffer, TEXT("\\"), reinterpret_cast(&lpFileInfo), &cbFileInfo); + if (cbFileInfo) + { + _major = (lpFileInfo->dwFileVersionMS & 0xFFFF0000) >> 16; + _minor = lpFileInfo->dwFileVersionMS & 0x0000FFFF; + _patch = (lpFileInfo->dwFileVersionLS & 0xFFFF0000) >> 16; + _build = lpFileInfo->dwFileVersionLS & 0x0000FFFF; + } + delete[] buffer; + } +} + +generic_string Version::toString() +{ + if (_build == 0 && _patch == 0 && _minor == 0 && _major == 0) // "" + { + return TEXT(""); + } + else if (_build == 0 && _patch == 0 && _minor == 0) // "major" + { + return std::to_wstring(_major); + } + else if (_build == 0 && _patch == 0) // "major.minor" + { + std::wstring v = std::to_wstring(_major); + v += TEXT("."); + v += std::to_wstring(_minor); + return v; + } + else if (_build == 0) // "major.minor.patch" + { + std::wstring v = std::to_wstring(_major); + v += TEXT("."); + v += std::to_wstring(_minor); + v += TEXT("."); + v += std::to_wstring(_patch); + return v; + } + + // "major.minor.patch.build" + std::wstring ver = std::to_wstring(_major); + ver += TEXT("."); + ver += std::to_wstring(_minor); + ver += TEXT("."); + ver += std::to_wstring(_patch); + ver += TEXT("."); + ver += std::to_wstring(_build); + + return ver; +} + +int Version::compareTo(const Version& v2c) const +{ + if (_major > v2c._major) + return 1; + else if (_major < v2c._major) + return -1; + else // (_major == v2c._major) + { + if (_minor > v2c._minor) + return 1; + else if (_minor < v2c._minor) + return -1; + else // (_minor == v2c._minor) + { + if (_patch > v2c._patch) + return 1; + else if (_patch < v2c._patch) + return -1; + else // (_patch == v2c._patch) + { + if (_build > v2c._build) + return 1; + else if (_build < v2c._build) + return -1; + else // (_build == v2c._build) + { + return 0; + } + } + } + } +} + +bool Version::isCompatibleTo(const Version& from, const Version& to) const +{ + // This method determinates if Version object is in between "from" version and "to" version, it's useful for testing compatibility of application. + // test in versions example: + // 1. <0.0.0.0, 0.0.0.0>: both from to versions are empty, so it's + // 2. <6.9, 6.9>: plugin is compatible to only v6.9 + // 3. <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) + // 4. <0.0.0.0, 8.2.1>: all version until v8.2.1 (included) + // 5. <8.3, 0.0.0.0>: from v8.3 (included) to the latest verrsion + + if (empty()) // if this version is empty, then no compatible to all version + return false; + + if (from.empty() && to.empty()) // both versions "from" and "to" are empty: it's considered compatible, whatever this version is (match to 1) + { + return true; + } + + if (from <= *this && to >= *this) // from_ver <= this_ver <= to_ver (match to 2, 3 and 4) + { + return true; + } + + if (from <= *this && to.empty()) // from_ver <= this_ver (match to 5) + { + return true; + } + + return false; +} diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index bc5e05d89..013081ca8 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -22,6 +22,7 @@ #include #include #include +#include const bool dirUp = true; @@ -231,3 +232,57 @@ int nbDigitsFromNbLines(size_t nbLines); generic_string getDateTimeStrFrom(const generic_string& dateTimeFormat, const SYSTEMTIME& st); HFONT createFont(const TCHAR* fontName, int fontSize, bool isBold, HWND hDestParent); + +class Version final +{ +public: + Version() = default; + Version(const generic_string& versionStr); + + void setVersionFrom(const generic_string& filePath); + generic_string toString(); + bool isNumber(const generic_string& s) const { + return !s.empty() && + find_if(s.begin(), s.end(), [](TCHAR c) { return !_istdigit(c); }) == s.end(); + }; + + int compareTo(const Version& v2c) const; + + bool operator < (const Version& v2c) const { + return compareTo(v2c) == -1; + }; + + bool operator <= (const Version& v2c) const { + int r = compareTo(v2c); + return r == -1 || r == 0; + }; + + bool operator > (const Version& v2c) const { + return compareTo(v2c) == 1; + }; + + bool operator >= (const Version& v2c) const { + int r = compareTo(v2c); + return r == 1 || r == 0; + }; + + bool operator == (const Version& v2c) const { + return compareTo(v2c) == 0; + }; + + bool operator != (const Version& v2c) const { + return compareTo(v2c) != 0; + }; + + bool empty() const { + return _major == 0 && _minor == 0 && _patch == 0 && _build == 0; + } + + bool isCompatibleTo(const Version& from, const Version& to) const; + +private: + unsigned long _major = 0; + unsigned long _minor = 0; + unsigned long _patch = 0; + unsigned long _build = 0; +}; diff --git a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp index 30dee5c6d..9ddd15cd1 100644 --- a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp +++ b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp @@ -21,6 +21,7 @@ #include #include "PluginsManager.h" #include "resource.h" +#include "pluginsAdmin.h" using namespace std; @@ -290,7 +291,7 @@ int PluginsManager::loadPlugin(const TCHAR *pluginFilePath) } } -bool PluginsManager::loadPluginsV2(const TCHAR* dir) +bool PluginsManager::loadPluginsV2(const TCHAR* dir, const PluginViewList* pluginUpdateInfoList) { if (_isDisabled) return false; @@ -317,6 +318,12 @@ bool PluginsManager::loadPluginsV2(const TCHAR* dir) HANDLE hFindFolder = ::FindFirstFile(pluginsFolderFilter.c_str(), &foundData); HANDLE hFindDll = INVALID_HANDLE_VALUE; + // Get Notepad++ current version + TCHAR nppFullPathName[MAX_PATH]; + GetModuleFileName(NULL, nppFullPathName, MAX_PATH); + Version nppVer; + nppVer.setVersionFrom(nppFullPathName); + // get plugin folder if (hFindFolder != INVALID_HANDLE_VALUE && (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { @@ -333,10 +340,31 @@ bool PluginsManager::loadPluginsV2(const TCHAR* dir) hFindDll = ::FindFirstFile(pluginsFullPathFilter.c_str(), &foundData); if (hFindDll != INVALID_HANDLE_VALUE && !(foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - dllNames.push_back(pluginsFullPathFilter); + // - foundFileName: folder-name + // _ pluginsFullPathFilter: version + // + // Find plugin update info of current plugin and check if it's compatible to Notepad++ current versions + bool isCompatible = true; - PluginList & pl = nppParams.getPluginList(); - pl.add(foundFileName, false); + if (pluginUpdateInfoList) + { + int index = 0; + PluginUpdateInfo* pui = pluginUpdateInfoList->findPluginInfoFromFolderName(foundFileName, index); + if (pui) + { + // Find plugin version + Version v; + v.setVersionFrom(pluginsFullPathFilter); + if (pui->_version == v) + { + // Find compatible Notepad++ versions + isCompatible = nppVer.isCompatibleTo(pui->_nppCompatibleVersions.first, pui->_nppCompatibleVersions.second); + } + } + } + + if (isCompatible) + dllNames.push_back(pluginsFullPathFilter); } } // get plugin folder @@ -361,10 +389,31 @@ bool PluginsManager::loadPluginsV2(const TCHAR* dir) hFindDll = ::FindFirstFile(pluginsFullPathFilter2.c_str(), &foundData); if (hFindDll != INVALID_HANDLE_VALUE && !(foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - dllNames.push_back(pluginsFullPathFilter2); + // - foundFileName2: folder-name + // _ pluginsFullPathFilter2: version + // + // Find plugin update info of current plugin and check if it's compatible to Notepad++ current versions + bool isCompatible2 = true; - PluginList & pl = nppParams.getPluginList(); - pl.add(foundFileName2, false); + if (pluginUpdateInfoList) + { + int index2 = 0; + PluginUpdateInfo* pui2 = pluginUpdateInfoList->findPluginInfoFromFolderName(foundFileName2, index2); + if (pui2) + { + // Find plugin version + Version v2; + v2.setVersionFrom(pluginsFullPathFilter2); + if (pui2->_version == v2) + { + // Find compatible Notepad++ versions + isCompatible2 = nppVer.isCompatibleTo(pui2->_nppCompatibleVersions.first, pui2->_nppCompatibleVersions.second); + } + } + } + + if (isCompatible2) + dllNames.push_back(pluginsFullPathFilter2); } } } diff --git a/PowerEditor/src/MISC/PluginsManager/PluginsManager.h b/PowerEditor/src/MISC/PluginsManager/PluginsManager.h index 2badc5d18..14a120d0b 100644 --- a/PowerEditor/src/MISC/PluginsManager/PluginsManager.h +++ b/PowerEditor/src/MISC/PluginsManager/PluginsManager.h @@ -23,6 +23,7 @@ #include "IDAllocator.h" typedef BOOL (__cdecl * PFUNCISUNICODE)(); +class PluginViewList; struct PluginCommand { @@ -86,7 +87,7 @@ public: } int loadPlugin(const TCHAR *pluginFilePath); - bool loadPluginsV2(const TCHAR *dir = NULL); + bool loadPluginsV2(const TCHAR *dir = NULL, const PluginViewList* pluginUpdateInfoList = nullptr); bool unloadPlugin(int index, HWND nppHandle); diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 6a1c752a2..1f740ad1b 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -408,7 +408,8 @@ LRESULT Notepad_plus::init(HWND hwnd) _scintillaCtrls4Plugins.init(_pPublicInterface->getHinst(), hwnd); _pluginsManager.init(nppData); - _pluginsManager.loadPluginsV2(nppParam.getPluginRootDir()); + bool enablePluginAdmin = _pluginsAdminDlg.initFromJson(); + _pluginsManager.loadPluginsV2(nppParam.getPluginRootDir(), enablePluginAdmin ? &_pluginsAdminDlg.getAvailablePluginUpdateInfoList() : nullptr); _restoreButton.init(_pPublicInterface->getHinst(), hwnd); // ------------ // @@ -525,7 +526,6 @@ LRESULT Notepad_plus::init(HWND hwnd) } //Plugin menu - bool enablePluginAdmin = _pluginsAdminDlg.isValide(); _pluginsAdminDlg.setPluginsManager(&_pluginsManager); _pluginsManager.initMenu(_mainMenuHandle, enablePluginAdmin); @@ -7110,7 +7110,7 @@ static const QuoteParams quotes[] = {TEXT("Anonymous #65"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("A man without God is like a fish without a bicycle.")}, {TEXT("Anonymous #66"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("I hate how spiders just sit there on the walls and act like they pay rent!")}, {TEXT("Anonymous #67"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Whenever someone starts a sentence by saying \"I'm not racist...\"),they are about to say something super racist.")}, - {TEXT("Anonymous #68"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("I'm not laughing at you, I'm laughing with you, you're just not laughing.")}, + {TEXT("Anonymous #68"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("I'm not laughing at you, I'm laughing with you, you're just not laughing.\n")}, {TEXT("Anonymous #69"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("Women need a reason to have sex. Men just need a place.")}, {TEXT("Anonymous #70"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("If abortion is murder then are condoms kidnapping?")}, {TEXT("Anonymous #71"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Men also have feelings.\nFor example, they can feel hungry.")}, @@ -7120,12 +7120,12 @@ static const QuoteParams quotes[] = {TEXT("Anonymous #75"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("I think therefore I am\nnot religious.")}, {TEXT("Anonymous #76"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Even if being gay were a choice, so what?\nPeople choose to be assholes and they can get married.")}, {TEXT("Anonymous #77"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Governments are like diapers.\nThey should be changed often, and for the same reason.")}, - {TEXT("Anonymous #78"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Mathématiquement, un cocu est un entier qui partage sa moitié avec un tiers.")}, - {TEXT("Anonymous #79"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("I'm a creationist.\nI believe man created God.")}, - {TEXT("Anonymous #80"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Let's eat kids.\nLet's eat, kids.\n\nUse a comma.\nSave lives.")}, + {TEXT("Anonymous #78"), QuoteParams::slow, true, SC_CP_UTF8, L_TEXT, TEXT("Mathématiquement, un cocu est un entier qui partage sa moitié avec un tiers.\n")}, + {TEXT("Anonymous #79"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("I'm a creationist.\nI believe man created God.\n")}, + {TEXT("Anonymous #80"), QuoteParams::slow, true, SC_CP_UTF8, L_TEXT, TEXT("Let's eat kids.\nLet's eat, kids.\n\nUse a comma.\nSave lives.\n")}, {TEXT("Anonymous #81"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("A male engineering student was crossing a road one day when a frog called out to him and said, \"If you kiss me, I'll turn into a beautiful princess.\" He bent over, picked up the frog, and put it in his pocket.\n\nThe frog spoke up again and said, \"If you kiss me and turn me back into a beautiful princess, I will stay with you for one week.\" The engineering student took the frog out of his pocket, smiled at it; and returned it to his pocket.\n\nThe frog then cried out, \"If you kiss me and turn me back into a princess, I'll stay with you and do ANYTHING you want.\" Again the boy took the frog out, smiled at it, and put it back into his pocket.\n\nFinally, the frog asked, \"What is the matter? I've told you I'm a beautiful princess, that I'll stay with you for a week and do anything you want. Why won't you kiss me?\" The boy said, \"Look I'm an engineer. I don't have time for a girlfriend, but a talking frog is cool.\"\n")}, - {TEXT("Anonymous #82"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Gamers never die.\nThey just go offline.")}, - {TEXT("Anonymous #83"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Copy from one, it's plagiarism.\nCopy from two, it's research.")}, + {TEXT("Anonymous #82"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Gamers never die.\nThey just go offline.\n")}, + {TEXT("Anonymous #83"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Copy from one, it's plagiarism.\nCopy from two, it's research.\n")}, {TEXT("Anonymous #84"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Saying that Java is nice because it works on all OSes is like saying that anal sex is nice because it works on all genders.")}, {TEXT("Anonymous #85"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Race, religion, ethnic pride and nationalism etc... does nothing but teach you how to hate people that you've never met.")}, {TEXT("Anonymous #86"), QuoteParams::rapid, true, SC_CP_UTF8, L_TEXT, TEXT("Farts are just the ghosts of the things we eat.")}, diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index 485cb9f2d..ef977efbb 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -2973,7 +2973,7 @@ void Notepad_plus::command(int id) if (isFirstTime) { _nativeLangSpeaker.changePluginsAdminDlgLang(_pluginsAdminDlg); - _pluginsAdminDlg.updateListAndLoadFromJson(); + _pluginsAdminDlg.updateList(); } break; } diff --git a/PowerEditor/src/Parameters.h b/PowerEditor/src/Parameters.h index a33b4a510..0f0d3a93e 100644 --- a/PowerEditor/src/Parameters.h +++ b/PowerEditor/src/Parameters.h @@ -1251,19 +1251,6 @@ private: }; -class PluginList final -{ -public : - void add(generic_string fn, bool isInBL) - { - _list.push_back(std::pair(fn, isInBL)); - } - -private: - std::vector>_list; -}; - - struct UdlXmlFileState final { TiXmlDocument* _udlXmlDoc = nullptr; bool _isDirty = false; @@ -1600,7 +1587,6 @@ public: return false; } - PluginList & getPluginList() {return _pluginList;}; bool importUDLFromFile(const generic_string& sourceFile); bool exportUDLToFile(size_t langIndex2export, const generic_string& fileName2save); NativeLangSpeaker* getNativeLangSpeaker() { @@ -1732,7 +1718,6 @@ private: std::vector _fontlist; std::vector _blacklist; - PluginList _pluginList; HMODULE _hUXTheme = nullptr; diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp index a7b2ab69a..ab834089b 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp @@ -35,148 +35,7 @@ using namespace std; using nlohmann::json; -Version::Version(const generic_string& versionStr) -{ - try { - auto ss = tokenizeString(versionStr, '.'); - if (ss.size() > 4) - throw wstring(TEXT("Version parts are more than 4. The string to parse is not a valid version format. Let's make it default value in catch block.")); - - int i = 0; - vector v = {&_major, &_minor, &_patch, &_build}; - for (const auto& s : ss) - { - if (!isNumber(s)) - { - throw wstring(TEXT("One of version character is not number. The string to parse is not a valid version format. Let's make it default value in catch block.")); - } - *(v[i]) = std::stoi(s); - - ++i; - } - } -#ifdef DEBUG - catch (const wstring& s) - { - _major = 0; - _minor = 0; - _patch = 0; - _build = 0; - - throw s; - } -#endif - catch (...) - { - _major = 0; - _minor = 0; - _patch = 0; - _build = 0; -#ifdef DEBUG - throw wstring(TEXT("Unknown exception from \"Version::Version(const generic_string& versionStr)\"")); -#endif - } -} - -void Version::setVersionFrom(const generic_string& filePath) -{ - if (!filePath.empty() && ::PathFileExists(filePath.c_str())) - { - DWORD uselessArg = 0; // this variable is for passing the ignored argument to the functions - DWORD bufferSize = ::GetFileVersionInfoSize(filePath.c_str(), &uselessArg); - - if (bufferSize <= 0) - return; - - unsigned char* buffer = new unsigned char[bufferSize]; - ::GetFileVersionInfo(filePath.c_str(), uselessArg, bufferSize, buffer); - - VS_FIXEDFILEINFO* lpFileInfo = nullptr; - UINT cbFileInfo = 0; - VerQueryValue(buffer, TEXT("\\"), reinterpret_cast(&lpFileInfo), &cbFileInfo); - if (cbFileInfo) - { - _major = (lpFileInfo->dwFileVersionMS & 0xFFFF0000) >> 16; - _minor = lpFileInfo->dwFileVersionMS & 0x0000FFFF; - _patch = (lpFileInfo->dwFileVersionLS & 0xFFFF0000) >> 16; - _build = lpFileInfo->dwFileVersionLS & 0x0000FFFF; - } - delete[] buffer; - } -} - -generic_string Version::toString() -{ - if (_build == 0 && _patch == 0 && _minor == 0 && _major == 0) // "" - { - return TEXT(""); - } - else if (_build == 0 && _patch == 0 && _minor == 0) // "major" - { - return std::to_wstring(_major); - } - else if (_build == 0 && _patch == 0) // "major.minor" - { - std::wstring v = std::to_wstring(_major); - v += TEXT("."); - v += std::to_wstring(_minor); - return v; - } - else if (_build == 0) // "major.minor.patch" - { - std::wstring v = std::to_wstring(_major); - v += TEXT("."); - v += std::to_wstring(_minor); - v += TEXT("."); - v += std::to_wstring(_patch); - return v; - } - - // "major.minor.patch.build" - std::wstring ver = std::to_wstring(_major); - ver += TEXT("."); - ver += std::to_wstring(_minor); - ver += TEXT("."); - ver += std::to_wstring(_patch); - ver += TEXT("."); - ver += std::to_wstring(_build); - - return ver; -} - -int Version::compareTo(const Version& v2c) const -{ - if (_major > v2c._major) - return 1; - else if (_major < v2c._major) - return -1; - else // (_major == v2c._major) - { - if (_minor > v2c._minor) - return 1; - else if (_minor < v2c._minor) - return -1; - else // (_minor == v2c._minor) - { - if (_patch > v2c._patch) - return 1; - else if (_patch < v2c._patch) - return -1; - else // (_patch == v2c._patch) - { - if (_build > v2c._build) - return 1; - else if (_build < v2c._build) - return -1; - else // (_build == v2c._build) - { - return 0; - } - } - } - } -} generic_string PluginUpdateInfo::describe() { @@ -643,7 +502,6 @@ void PluginViewList::pushBack(PluginUpdateInfo* pi) values2Add.push_back(pi->_displayName); Version v = pi->_version; values2Add.push_back(v.toString()); - //values2Add.push_back(TEXT("Yes")); // add in order size_t i = _ui.findAlphabeticalOrderPos(pi->_displayName, _sortType == DISPLAY_NAME_ALPHABET_ENCREASE ? _ui.sortEncrease : _ui.sortDecrease); @@ -700,7 +558,7 @@ std::pair getIntervalVersions(generic_string intervalVerStr) return result; } -bool loadFromJson(PluginViewList & pl, const json& j) +bool loadFromJson(std::vector& pl, const json& j) { if (j.empty()) return false; @@ -714,65 +572,6 @@ bool loadFromJson(PluginViewList & pl, const json& j) for (const auto& i : jArray) { try { - - // Optional - std::pair _nppCompatibleVersions; // compatible to Notepad++ interval versions: example: - // <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions (due to invalid format set) - // <6.9, 6.9>: plugin is compatible to only v6.9 - // <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) - // <0.0.0.0, 8.2.1> all until v8.2.1 (included) - // <8.3, 0.0.0.0> from v8.3 (included) to all - if (i.contains("npp-compatible-versions")) - { - json jNppCompatibleVer = i["npp-compatible-versions"]; - - string versionsStr = jNppCompatibleVer.get(); - generic_string nppCompatibleVersionStr(versionsStr.begin(), versionsStr.end()); - std::pair nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr); - - // nppCompatibleVersions contains compatibilty to Notepad++ versions example: - // <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions - // <6.9, 6.9>: plugin is compatible to only v6.9 - // <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) - // <0.0.0.0, 8.2.1>: all version until v8.2.1 (included) - // <8.3, 0.0.0.0>: from v8.3 (included) to the latest verrsion - - if (nppCompatibleVersions.first == nppCompatibleVersions.second && nppCompatibleVersions.first.empty()) // compatible versions not set - // 1 case is processed: - // <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions - { - // OK - do nothing - } - else - { - TCHAR nppFullPathName[MAX_PATH]; - GetModuleFileName(NULL, nppFullPathName, MAX_PATH); - - Version nppVer; - nppVer.setVersionFrom(nppFullPathName); - - if (nppCompatibleVersions.first <= nppVer && nppCompatibleVersions.second >= nppVer) // from <= npp <= to - // 3 cases are processed: - // <6.9, 6.9>: plugin is compatible to only v6.9 - // <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) - // <0.0.0.0, 8.2.1>: all versions until v8.2.1 (included) - { - // OK - do nothing - } - else if (nppCompatibleVersions.first <= nppVer && nppCompatibleVersions.second.empty()) // from <= npp <= to - // 1 case is processed: - // <8.3, 0.0.0.0>: from v8.3 (included) to the latest version - { - // OK - do nothing - } - else // Not compatible to Notepad++ current version - { - // Not OK - skip this plugin - continue; - } - } - } - PluginUpdateInfo* pi = new PluginUpdateInfo(); string valStr = i.at("folder-name").get(); @@ -794,6 +593,15 @@ bool loadFromJson(PluginViewList & pl, const json& j) generic_string newValStr(valStr.begin(), valStr.end()); pi->_version = Version(newValStr); + if (i.contains("npp-compatible-versions")) + { + json jNppCompatibleVer = i["npp-compatible-versions"]; + + string versionsStr = jNppCompatibleVer.get(); + generic_string nppCompatibleVersionStr(versionsStr.begin(), versionsStr.end()); + pi->_nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr); + } + valStr = i.at("repository").get(); pi->_repository = wmc.char2wchar(valStr.c_str(), CP_ACP); @@ -801,7 +609,7 @@ bool loadFromJson(PluginViewList & pl, const json& j) pi->_homepage = wmc.char2wchar(valStr.c_str(), CP_ACP); - pl.pushBack(pi); + pl.push_back(pi); } #ifdef DEBUG catch (const wstring& s) @@ -845,7 +653,7 @@ PluginUpdateInfo::PluginUpdateInfo(const generic_string& fullFilePath, const gen typedef const char * (__cdecl * PFUNCGETPLUGINLIST)(); -bool PluginsAdminDlg::isValide() +bool PluginsAdminDlg::initFromJson() { // GUP.exe doesn't work under XP winVer winVersion = (NppParameters::getInstance()).getWinVersion(); @@ -864,44 +672,29 @@ bool PluginsAdminDlg::isValide() return false; } + json j; + #ifdef DEBUG // if not debug, then it's release - return true; + // load from nppPluginList.json instead of nppPluginList.dll + ifstream nppPluginListJson(_pluginListFullPath); + nppPluginListJson >> j; #else //RELEASE // check the signature on default location : %APPDATA%\Notepad++\plugins\config\pl\nppPluginList.dll or NPP_INST_DIR\plugins\config\pl\nppPluginList.dll SecurityGard securityGard; - bool isOK = securityGard.checkModule(_pluginListFullPath, nm_pluginList); + bool isSecured = securityGard.checkModule(_pluginListFullPath, nm_pluginList); - if (!isOK) - return isOK; + if (!isSecured) + return false; - isOK = securityGard.checkModule(_updaterFullPath, nm_gup); - return isOK; -#endif -} + isSecured = securityGard.checkModule(_updaterFullPath, nm_gup); -bool PluginsAdminDlg::updateListAndLoadFromJson() -{ - HMODULE hLib = NULL; - - try + if (isSecured) { - if (!isValide()) - return false; - - json j; - -#ifdef DEBUG // if not debug, then it's release - - // load from nppPluginList.json instead of nppPluginList.dll - ifstream nppPluginListJson(_pluginListFullPath); - nppPluginListJson >> j; - -#else //RELEASE - + HMODULE hLib = NULL; hLib = ::LoadLibraryEx(_pluginListFullPath.c_str(), 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); if (!hLib) @@ -936,39 +729,56 @@ bool PluginsAdminDlg::updateListAndLoadFromJson() delete[] buffer; -#endif - // if absent then download it - - - // check the update for nppPluginList.json - - - // download update if present - - - // load pl.json - // - - loadFromJson(_availableList, j); - - // initialize update list view - checkUpdates(); - - // initialize installed list view - loadFromPluginInfos(); - ::FreeLibrary(hLib); - return true; - } - catch (...) - { - // whichever exception - if (hLib) - ::FreeLibrary(hLib); - return false; } +#endif + + + return loadFromJson(_availableList._list, j); } +bool PluginsAdminDlg::updateList() +{ + // initialize the primary view with the plugin list loaded from json + initAvailablePluginsViewFromList(); + + // initialize update list view + checkUpdates(); + + // initialize installed list view + loadFromPluginInfos(); + + return true; +} + + +bool PluginsAdminDlg::initAvailablePluginsViewFromList() +{ + TCHAR nppFullPathName[MAX_PATH]; + GetModuleFileName(NULL, nppFullPathName, MAX_PATH); + + Version nppVer; + nppVer.setVersionFrom(nppFullPathName); + + for (const auto& i : _availableList._list) + { + bool isCompatible = nppVer.isCompatibleTo(i->_nppCompatibleVersions.first, i->_nppCompatibleVersions.second); + + if (isCompatible) + { + vector values2Add; + values2Add.push_back(i->_displayName); + Version v = i->_version; + values2Add.push_back(v.toString()); + + // add in order + size_t j = _availableList._ui.findAlphabeticalOrderPos(i->_displayName, _availableList._sortType == DISPLAY_NAME_ALPHABET_ENCREASE ? ListView::sortEncrease : ListView::sortDecrease); + _availableList._ui.addLine(values2Add, reinterpret_cast(i), static_cast(j)); + } + } + + return true; +} bool PluginsAdminDlg::loadFromPluginInfos() { diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h index 8efdfef0d..798d22565 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h @@ -26,56 +26,6 @@ class PluginsManager; -struct Version -{ - unsigned long _major = 0; - unsigned long _minor = 0; - unsigned long _patch = 0; - unsigned long _build = 0; - - Version() = default; - Version(const generic_string& versionStr); - - void setVersionFrom(const generic_string& filePath); - generic_string toString(); - bool isNumber(const generic_string& s) const { - return !s.empty() && - find_if(s.begin(), s.end(), [](_TCHAR c) { return !_istdigit(c); }) == s.end(); - }; - - int compareTo(const Version& v2c) const; - - bool operator < (const Version& v2c) const { - return compareTo(v2c) == -1; - }; - - bool operator <= (const Version& v2c) const { - int r = compareTo(v2c); - return r == -1 || r == 0; - }; - - bool operator > (const Version& v2c) const { - return compareTo(v2c) == 1; - }; - - bool operator >= (const Version& v2c) const { - int r = compareTo(v2c); - return r == 1 || r == 0; - }; - - bool operator == (const Version& v2c) const { - return compareTo(v2c) == 0; - }; - - bool operator != (const Version& v2c) const { - return compareTo(v2c) != 0; - }; - - bool empty() const { - return _major == 0 && _minor == 0 && _patch == 0 && _build == 0; - } -}; - struct PluginUpdateInfo { generic_string _fullFilePath; // only for the installed Plugin @@ -83,6 +33,13 @@ struct PluginUpdateInfo generic_string _folderName; // plugin folder name - should be the same name with plugin and should be uniq among the plugins generic_string _displayName; // plugin description name Version _version; + // Optional + std::pair _nppCompatibleVersions; // compatible to Notepad++ interval versions: example: + // <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions (due to invalid format set) + // <6.9, 6.9>: plugin is compatible to only v6.9 + // <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) + // <0.0.0.0, 8.2.1> all until v8.2.1 (included) + // <8.3, 0.0.0.0> from v8.3 (included) to all generic_string _homepage; generic_string _sourceUrl; generic_string _description; @@ -128,6 +85,8 @@ struct SortDisplayNameDecrease final class PluginViewList { +friend class PluginsAdminDlg; + public: PluginViewList() = default; ~PluginViewList() { @@ -196,12 +155,12 @@ public : display(); }; - bool isValide(); + bool initFromJson(); void switchDialog(int indexToSwitch); void setPluginsManager(PluginsManager *pluginsManager) { _pPluginsManager = pluginsManager; }; - bool updateListAndLoadFromJson(); + bool updateList(); void setAdminMode(bool isAdm) { _nppCurrentStatus._isAdminMode = isAdm; }; bool installPlugins(); @@ -211,6 +170,9 @@ public : void changeTabName(LIST_TYPE index, const TCHAR *name2change); void changeColumnName(COLUMN_TYPE index, const TCHAR *name2change); generic_string getPluginListVerStr() const; + const PluginViewList & getAvailablePluginUpdateInfoList() const { + return _availableList; + }; protected: virtual intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam); @@ -243,6 +205,7 @@ private : return searchFromCurrentSel(str2search, _inDescs, isNextMode); }; + bool initAvailablePluginsViewFromList(); bool loadFromPluginInfos(); bool checkUpdates();