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 (a06b404708).
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
This commit is contained in:
Don Ho 2022-03-06 02:08:04 +01:00
parent f285c5983a
commit f9118dd13c
9 changed files with 381 additions and 343 deletions

View File

@ -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<unsigned long*> 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<LPVOID*>(&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 <from, to> 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;
}

View File

@ -22,6 +22,7 @@
#include <cstdint>
#include <unordered_set>
#include <algorithm>
#include <tchar.h>
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;
};

View File

@ -21,6 +21,7 @@
#include <cinttypes>
#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);
}
}
}

View File

@ -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);

View File

@ -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.")},

View File

@ -2973,7 +2973,7 @@ void Notepad_plus::command(int id)
if (isFirstTime)
{
_nativeLangSpeaker.changePluginsAdminDlgLang(_pluginsAdminDlg);
_pluginsAdminDlg.updateListAndLoadFromJson();
_pluginsAdminDlg.updateList();
}
break;
}

View File

@ -1251,19 +1251,6 @@ private:
};
class PluginList final
{
public :
void add(generic_string fn, bool isInBL)
{
_list.push_back(std::pair<generic_string, bool>(fn, isInBL));
}
private:
std::vector<std::pair<generic_string, bool>>_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<generic_string> _fontlist;
std::vector<generic_string> _blacklist;
PluginList _pluginList;
HMODULE _hUXTheme = nullptr;

View File

@ -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<unsigned long*> 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<LPVOID*>(&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<Version, Version> getIntervalVersions(generic_string intervalVerStr)
return result;
}
bool loadFromJson(PluginViewList & pl, const json& j)
bool loadFromJson(std::vector<PluginUpdateInfo*>& 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<Version, Version> _nppCompatibleVersions; // compatible to Notepad++ interval versions: <from, to> 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<std::string>();
generic_string nppCompatibleVersionStr(versionsStr.begin(), versionsStr.end());
std::pair<Version, Version> nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr);
// nppCompatibleVersions contains compatibilty to Notepad++ versions <from, to> 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<std::string>();
@ -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<std::string>();
generic_string nppCompatibleVersionStr(versionsStr.begin(), versionsStr.end());
pi->_nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr);
}
valStr = i.at("repository").get<std::string>();
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<generic_string> 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<LPARAM>(i), static_cast<int>(j));
}
}
return true;
}
bool PluginsAdminDlg::loadFromPluginInfos()
{

View File

@ -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<Version, Version> _nppCompatibleVersions; // compatible to Notepad++ interval versions: <from, to> 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();