ModernSettings: Remove duplicates

Windows started to add newer version of settings to settings description
file. These have the same description as older settings, but use
different parameters.

Unfortunately old settings are still present.
This causes our modern settings folder to contain duplicates.
And also we tend to use older setting definitions that no longer work
properly.

Thus we will de-duplicate parsed settings and try to keep newer ones
(that should work better).
New settings tend to have numeric suffix, so we will keep those with
biggest suffix.

Fixes #1031
This commit is contained in:
ge0rdi
2022-12-10 14:07:03 +01:00
parent 658981adf7
commit 2a7fc0034c
2 changed files with 39 additions and 8 deletions

View File

@@ -10,6 +10,7 @@
#include <appmodel.h>
#include <Shlobj.h>
#include <Shlwapi.h>
#include <algorithm>
#include <functional>
#include <iterator>
#include <mutex>
@@ -316,9 +317,9 @@ static std::vector<uint8_t> ParseSetting(CComPtr<IXMLDOMNode>& parent)
return writer.buffer();
}
static std::vector<uint8_t> ParseModernSettings()
static std::vector<std::vector<uint8_t>> ParseModernSettings()
{
AttributeWriter writer;
std::vector<std::vector<uint8_t>> retval;
CComPtr<IXMLDOMDocument> doc;
if (SUCCEEDED(doc.CoCreateInstance(L"Msxml2.FreeThreadedDOMDocument")))
@@ -335,16 +336,13 @@ static std::vector<uint8_t> ParseModernSettings()
CComPtr<IXMLDOMNode> root;
if (doc->selectSingleNode(CComBSTR(L"PCSettings"), &root) == S_OK)
{
FileHdr hdr{};
writer.addBlob(Id::Header, &hdr, sizeof(hdr));
CComPtr<IXMLDOMNode> node;
root->get_firstChild(&node);
while (node)
{
auto buffer = ParseSetting(node);
if (!buffer.empty())
writer.addBlob(Id::Blob, buffer.data(), buffer.size());
retval.push_back(std::move(buffer));
CComPtr<IXMLDOMNode> next;
if (FAILED(node->get_nextSibling(&next)))
@@ -355,6 +353,19 @@ static std::vector<uint8_t> ParseModernSettings()
}
}
return retval;
}
static std::vector<uint8_t> SerializeModernSettings(const std::vector<std::vector<uint8_t>>& settings)
{
AttributeWriter writer;
FileHdr hdr{};
writer.addBlob(Id::Header, &hdr, sizeof(hdr));
for (const auto& setting : settings)
writer.addBlob(Id::Blob, setting.data(), setting.size());
return writer.buffer();
}
@@ -480,11 +491,30 @@ std::shared_ptr<ModernSettings> GetModernSettings()
s_settings.reset();
// re-parse settings
auto buffer = ParseModernSettings();
if (!buffer.empty())
auto settings = ParseModernSettings();
if (!settings.empty())
{
// sort by setting name (in reverse order)
// this way we will have newer settings (like SomeSetting-2) before older ones
std::stable_sort(settings.begin(), settings.end(), [](const auto& a, const auto& b) {
return ModernSettings::Setting(a).fileName > ModernSettings::Setting(b).fileName;
});
// now sort by description (strings presented to the user)
// and keep relative order of items with the same description
std::stable_sort(settings.begin(), settings.end(), [](const auto& a, const auto& b) {
return ModernSettings::Setting(a).description < ModernSettings::Setting(b).description;
});
// remove duplicates
settings.erase(std::unique(settings.begin(), settings.end(), [](const auto& a, const auto& b) {
return ModernSettings::Setting(a).description == ModernSettings::Setting(b).description;
}), settings.end());
// store to file
{
auto buffer = SerializeModernSettings(settings);
File f(path.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS);
if (f)
{

View File

@@ -121,6 +121,7 @@ public:
Setting() = default;
Setting(const Blob& blob);
Setting(const std::vector<uint8_t>& blob) : Setting(Blob{ blob.data(), blob.size() }) {}
explicit operator bool() const
{