diff --git a/.gitmodules b/.gitmodules
index 906e026..e54a7a8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -31,3 +31,6 @@
[submodule "deps/fifo_map"]
path = deps/fifo_map
url = git@github.com:nlohmann/fifo_map.git
+[submodule "deps/Shortcuts_VDF"]
+ path = deps/Shortcuts_VDF
+ url = git@github.com:Alia5/Shortcuts_VDF.git
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj
index a52c38d..2033835 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj
+++ b/GlosSIConfig/GlosSIConfig.vcxproj
@@ -68,7 +68,7 @@
/Zc:__cplusplus /Zc:twoPhase- %(AdditionalOptions)
false
NOMINMAX;%(PreprocessorDefinitions)
- ..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)
+ ..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories)
true
@@ -90,7 +90,7 @@
/Zc:__cplusplus /Zc:zwoPhase- /permissive- %(AdditionalOptions)
false
NOMINMAX;%(PreprocessorDefinitions)
- ..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)
+ ..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories)
true
@@ -153,7 +153,6 @@
-
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters
index ff925f0..e1d59d1 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj.filters
+++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters
@@ -84,9 +84,6 @@
Header Files
-
- Header Files
-
diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc
index 49f67af..ee15a05 100644
--- a/GlosSIConfig/Resource.rc
+++ b/GlosSIConfig/Resource.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,0,8,001000606002
- PRODUCTVERSION 0,0,8,001000606002
+ FILEVERSION 0,0,8,003002880001
+ PRODUCTVERSION 0,0,8,003002880001
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -69,12 +69,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Peter Repukat - FlatspotSoftware"
VALUE "FileDescription", "GlosSI - Config"
- VALUE "FileVersion", "0.0.8.0-1-gd6c6ef2"
+ VALUE "FileVersion", "0.0.8.0-3-g288bba1"
VALUE "InternalName", "GlosSIConfig"
VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSIConfig.exe"
VALUE "ProductName", "GlosSI"
- VALUE "ProductVersion", "0.0.8.0-1-gd6c6ef2"
+ VALUE "ProductVersion", "0.0.8.0-3-g288bba1"
END
END
BLOCK "VarFileInfo"
@@ -556,6 +556,206 @@ IDI_ICON1 ICON "..\GloSC_Icon.ico"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GlosSIConfig/ShortcutsVDF.h b/GlosSIConfig/ShortcutsVDF.h
deleted file mode 100644
index 3d03852..0000000
--- a/GlosSIConfig/ShortcutsVDF.h
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
-Copyright 2021-2022 Peter Repukat - FlatspotSoftware
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-namespace VDFParser {
-
-namespace internal {
- constexpr unsigned int str2int(const char* str, int h = 0)
- {
- return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
- }
-}
-
-
-namespace crc {
-template
-uint32_t calculate_crc(CONT container)
-{
- uint32_t crc32_table[256];
- for (uint32_t i = 0; i < 256; i++) {
- uint32_t ch = i;
- uint32_t crc = 0;
- for (size_t j = 0; j < 8; j++) {
- const uint32_t b = (ch ^ crc) & 1;
- crc >>= 1;
- if (b)
- crc = crc ^ 0xEDB88320;
- ch >>= 1;
- }
- crc32_table[i] = crc;
- }
- uint32_t crc = 0xFFFFFFFF;
- for (size_t i = 0; i < container.size(); i++) {
- const char ch = container.data()[i];
- const uint32_t t = (ch ^ crc) & 0xFF;
- crc = (crc >> 8) ^ crc32_table[t];
- }
- return ~crc;
-}
-} // namespace crc
-
-enum VDFTypeId {
- Map = 0,
- String,
- Number,
- EndMarker = 0x08
-};
-
-static constexpr const char k_appid[] = {"appid"};
-static constexpr const char k_appname[] = {"appname"};
-static constexpr const char k_exe[] = {"exe"};
-static constexpr const char k_StartDir[] = {"StartDir"};
-static constexpr const char k_icon[] = {"icon"};
-static constexpr const char k_ShortcutPath[] = {"ShortcutPath"};
-static constexpr const char k_LaunchOptions[] = {"LaunchOptions"};
-static constexpr const char k_IsHidden[] = {"IsHidden"};
-static constexpr const char k_AllowDesktopConfig[] = {"AllowDesktopConfig"};
-static constexpr const char k_AllowOverlay[] = {"AllowOverlay"};
-static constexpr const char k_openvr[] = {"openvr"};
-static constexpr const char k_Devkit[] = {"Devkit"};
-static constexpr const char k_DevkitGameID[] = {"DevkitGameID"};
-static constexpr const char k_DevkitOverrideAppID[] = {"DevkitOverrideAppID"};
-static constexpr const char k_LastPlayTime[] = {"LastPlayTime"};
-static constexpr const char k_FlatpakAppID[] = {"FlatpakAppID"};
-static constexpr const char k_tags[] = {"tags"};
-
-static const std::string SHORTCUTS_IDENTIFIER = "shortcuts";
-
-static inline const std::vector VDF_KEYS = {
- k_appid,
- k_appname,
- k_exe,
- k_StartDir,
- k_icon,
- k_ShortcutPath,
- k_LaunchOptions,
- k_IsHidden,
- k_AllowDesktopConfig,
- k_AllowOverlay,
- k_openvr,
- k_Devkit,
- k_DevkitGameID,
- k_DevkitOverrideAppID,
- k_LastPlayTime,
- k_FlatpakAppID,
- k_tags
-};
-struct VDFValue {
- VDFTypeId type = EndMarker;
- std::any value{};
-
- [[nodiscard]] std::string to_json() const
- {
- if (!value.has_value()) {
- return "null";
- }
- switch (type) {
- case Number:
- return std::to_string(std::any_cast(value));
- case String:
- return "\"" + std::regex_replace(std::regex_replace(std::any_cast(value), std::regex(R"(\\)"), R"(\\)"), std::regex(R"(")"), R"(\")") + "\"";
- case Map: {
- const auto& map = std::any_cast>(value);
- std::string res = "{\n";
- for (const auto& [key, v] : map) {
- res += "\"" + key + "\": " + v.to_json() + ",\n";
- }
- if (res.ends_with(",\n")) {
- res.pop_back();
- res.pop_back();
- }
- return res + "\n}";
- }
- case EndMarker:
- // WTF?!
- return "\"EndMarker\"";
- default:
- return "null";
- }
- }
-
- operator std::string() const
- {
- return to_json();
- }
-};
-
-static inline const nlohmann::fifo_map DEFAULT_SHORTCUT_MAP = {
- { k_appid, {VDFTypeId::Number, 0}},
- { k_appname, {VDFTypeId::String, ""}},
- { k_exe, {VDFTypeId::String, "\"\""}},
- { k_StartDir, {VDFTypeId::String, "\"\""}},
- { k_icon, {VDFTypeId::String, "\"\""}},
- { k_ShortcutPath, {VDFTypeId::String, "\"\""}},
- { k_LaunchOptions, {VDFTypeId::String, ""}},
- { k_IsHidden, {VDFTypeId::Number, ""}},
- { k_AllowDesktopConfig, {VDFTypeId::Number, 0}},
- { k_AllowOverlay, {VDFTypeId::Number, 1}},
- { k_openvr, {VDFTypeId::Number, 0}},
- { k_Devkit, {VDFTypeId::Number, 0}},
- { k_DevkitGameID, {VDFTypeId::String, ""}},
- { k_DevkitOverrideAppID, {VDFTypeId::Number, 0}},
- { k_LastPlayTime, {VDFTypeId::Number, ""}},
- { k_FlatpakAppID, {VDFTypeId::String, ""}},
- { k_tags, {VDFTypeId::Map, nlohmann::fifo_map < std::string, VDFValue >()}},
-};
-
-struct Shortcut {
- uint32_t appid{};
- std::string appname;
- std::string exe;
- std::string StartDir;
- std::string icon;
- std::string ShortcutPath;
- std::string LaunchOptions;
- uint32_t IsHidden{};
- uint32_t AllowDesktopConfig{};
- uint32_t AllowOverlay{};
- uint32_t openvr{};
- uint32_t Devkit{};
- std::string DevkitGameID;
- uint32_t DevkitOverrideAppID{};
- uint32_t LastPlayTime{};
- std::string FlatpakAppID;
- std::vector tags;
-
- nlohmann::fifo_map unsupported_keys;
-
- Shortcut() = default;
- explicit Shortcut(const nlohmann::fifo_map& vdf_map) : Shortcut()
- {
- for (const auto& [key, value] : (vdf_map.empty() ? DEFAULT_SHORTCUT_MAP : vdf_map)) {
- switch (value.type) {
- case Number: {
- switch (internal::str2int(key.c_str())) {
- case internal::str2int(k_appid):
- appid = std::any_cast(value.value);
- break;
- case internal::str2int(k_IsHidden):
- IsHidden = std::any_cast(value.value);
- break;
- case internal::str2int(k_AllowDesktopConfig):
- AllowDesktopConfig = std::any_cast(value.value);
- break;
- case internal::str2int(k_AllowOverlay):
- AllowOverlay = std::any_cast(value.value);
- break;
- case internal::str2int(k_openvr):
- openvr = std::any_cast(value.value);
- break;
- case internal::str2int(k_Devkit):
- Devkit = std::any_cast(value.value);
- break;
- case internal::str2int(k_DevkitOverrideAppID):
- DevkitOverrideAppID = std::any_cast(value.value);
- break;
- case internal::str2int(k_LastPlayTime):
- LastPlayTime = std::any_cast(value.value);
- break;
- default:
- unsupported_keys[key] = value;
- break;
- }
- break;
- case String: {
- switch (internal::str2int(key.c_str())) {
- case internal::str2int(k_appname):
- appname = std::any_cast(value.value);
- break;
- case internal::str2int(k_exe):
- exe = std::any_cast(value.value);
- break;
- case internal::str2int(k_StartDir):
- StartDir = std::any_cast(value.value);
- break;
- case internal::str2int(k_icon):
- icon = std::any_cast(value.value);
- break;
- case internal::str2int(k_ShortcutPath):
- ShortcutPath = std::any_cast(value.value);
- break;
- case internal::str2int(k_LaunchOptions):
- LaunchOptions = std::any_cast(value.value);
- break;
- case internal::str2int(k_DevkitGameID):
- DevkitGameID = std::any_cast(value.value);
- break;
- case internal::str2int(k_FlatpakAppID):
- FlatpakAppID = std::any_cast(value.value);
- break;
- default:
- unsupported_keys[key] = value;
- break;
- }
- break;
- }
- case Map: {
- switch (internal::str2int(key.c_str())) {
- case internal::str2int(k_tags): {
- for (const auto& [type, tag] : std::any_cast>(value.value) | std::views::values) {
- if (type == String) {
- tags.push_back(std::any_cast(tag));
- }
- }
- break;
- }
- default:
- unsupported_keys[key] = value;
- break;
- }
- break;
- }
- }
- }
- }
- }
-
- [[nodiscard]] uint32_t calculateAppId() const
- {
- const auto checksum = crc::calculate_crc(exe + appname);
- return checksum | 0x80000000;
- }
-
- operator VDFValue() const
- {
- nlohmann::fifo_map value;
- value[k_appid] = {Number, appid ? appid : calculateAppId()};
- value[k_appname] = {String, appname};
- value[k_exe] = {String, exe};
- value[k_StartDir] = {String, StartDir};
- value[k_icon] = {String, icon};
- value[k_ShortcutPath] = {String, ShortcutPath};
- value[k_LaunchOptions] = {String, LaunchOptions};
- value[k_IsHidden] = {Number, IsHidden};
- value[k_AllowDesktopConfig] = {Number, AllowDesktopConfig};
- value[k_AllowOverlay] = {Number, AllowOverlay};
- value[k_openvr] = {Number, openvr};
- value[k_Devkit] = {Number, Devkit};
- value[k_DevkitGameID] = {String, DevkitGameID};
- value[k_DevkitOverrideAppID] = {Number, DevkitOverrideAppID};
- value[k_LastPlayTime] = {Number, LastPlayTime};
- value[k_FlatpakAppID] = {String, FlatpakAppID};
-
- nlohmann::fifo_map tag_map;
- for (size_t i = 0; i < tags.size(); i++) {
- tag_map[std::to_string(i)] = {String,tags[i]};
- }
- value[k_tags] = {Map, tag_map};
-
- for (const auto& [key, v] : unsupported_keys) {
- value[key] = v;
- }
-
- return {Map, value};
- }
-};
-
-class Parser {
- private:
- static inline std::ifstream ifile;
- static inline std::ofstream ofile;
-
- template
- static inline auto readVDFValue()
- {
- uint8_t buff[sizeof(typ)];
- ifile.read((char*)buff, sizeof(typ));
- return *reinterpret_cast(buff);
- }
-
- template <>
- static inline auto readVDFValue()
- {
- std::string str;
- char ch = '\x0';
- do {
- if (ifile.eof()) {
- return str;
- }
- ifile.read(&ch, sizeof(char));
- if (ch != '\x0')
- str.push_back(ch);
- } while (ch != '\x0');
- return str;
- }
-
- template <>
- static inline auto readVDFValue>()
- {
- auto res = nlohmann::fifo_map();
- while (true) {
- const auto& [key, value] = readVDFValue();
- if (value.type == EndMarker) {
- return res;
- }
- res[key] = value;
- }
- }
-
- static inline std::pair readVDFValue()
- {
- auto res = std::pair("", VDFValue(EndMarker, nullptr));
-
- if (ifile.eof()) {
- return res;
- }
- const auto tid = static_cast(readVDFValue());
- if (tid == EndMarker) {
- return res;
- }
- res.second.type = tid;
- res.first = readVDFValue();
- switch (tid) {
- case VDFTypeId::Map:
- res.second.value = readVDFValue>();
- break;
- case VDFTypeId::Number:
- res.second.value = readVDFValue();
- break;
- case VDFTypeId::String:
- res.second.value = readVDFValue();
- break;
- default:
- throw std::exception("VDF: Unknown TypeID");
- break;
- }
-
- return res;
- }
-
- template
- static inline auto writeVDFValue(typ v)
- {
- ofile.write((char*)&v, sizeof(typ));
- }
-
- template <>
- static inline auto writeVDFValue(std::string v)
- {
- ofile.write(v.data(), v.length());
- ofile.write("\x00", 1);
- }
-
- template <>
- static inline auto writeVDFValue>(nlohmann::fifo_map v)
- {
- for (const auto& pair : v) {
- writeVDFValue(pair);
- }
- ofile.write("\x08", 1);
- }
-
- static inline void writeVDFValue(const std::pair& value)
- {
- ofile.write((char*)(&value.second.type), 1);
- writeVDFValue(value.first);
- switch (value.second.type) {
- case Map:
- writeVDFValue(std::any_cast>(value.second.value));
- break;
- case Number:
- writeVDFValue(std::any_cast(value.second.value));
- break;
- case String:
- writeVDFValue(std::any_cast(value.second.value));
- break;
- default:
- throw std::exception("VDF: Unknown TypeID");
- break;
- }
- }
-
- public:
- template
- static inline std::vector parseShortcuts(const std::filesystem::path& path, LogStream l = std::cout)
- {
-
- ifile.open(path, std::ios::binary | std::ios::in);
- if (!ifile.is_open()) {
- return {};
- }
-
- const auto& shortcutsVDF = readVDFValue();
- ifile.close();
- if (shortcutsVDF.second.type != Map || shortcutsVDF.first != SHORTCUTS_IDENTIFIER) {
- throw std::exception("invalid shortcuts file!");
- }
-
- const auto& v = std::any_cast>(shortcutsVDF.second.value);
-
- std::vector shortcuts;
- for (const auto& [type, sc] : v | std::views::values) {
- if (type != Map) {
- // throw std::exception("invalid shortcuts file!");
- // TODO: warn unsupported
- l << "unsupported or invalid shortcuts-file!";
- continue;
- }
- shortcuts.emplace_back(std::any_cast>(sc));
- }
-
- return shortcuts;
- }
-
- template
- static inline bool writeShortcuts(const std::filesystem::path& path, const std::vector& shortcuts, LogStream l = std::cout)
- {
- const auto backupFileName = path.wstring() + L".bak";
- if (std::filesystem::exists(path) && !std::filesystem::exists(backupFileName)) {
- l << "No shortcuts backup detected... Creating now...";
- const auto copied = std::filesystem::copy_file(path, backupFileName, std::filesystem::copy_options::update_existing);
- l << "failed to copy shortcuts.vdf to backup!";
- }
-
- ofile.open(path.wstring(), std::ios::binary | std::ios::out);
- if (!ofile.is_open()) {
- return false;
- }
- nlohmann::fifo_map shortcuts_map;
- for (size_t i = 0; i < shortcuts.size(); i++) {
- shortcuts_map[std::to_string(i)] = shortcuts[i];
- }
-
- writeVDFValue({SHORTCUTS_IDENTIFIER, {Map, shortcuts_map}});
- ofile.write("\x08", 1);
- ofile.close();
- return true;
- }
-};
-} // namespace VDFParser
diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h
index 0a2f7d6..d9c1595 100644
--- a/GlosSIConfig/UIModel.h
+++ b/GlosSIConfig/UIModel.h
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
-#include "ShortcutsVDF.h"
+#include
#include
#include
#include
diff --git a/deps/Shortcuts_VDF b/deps/Shortcuts_VDF
new file mode 160000
index 0000000..2816b31
--- /dev/null
+++ b/deps/Shortcuts_VDF
@@ -0,0 +1 @@
+Subproject commit 2816b31c8e777c2920e1f0881ce10c5c66e30c63