diff --git a/.gitmodules b/.gitmodules
index c9b93ef..906e026 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,3 +28,6 @@
[submodule "deps/traypp"]
path = deps/traypp
url = https://github.com/Soundux/traypp.git
+[submodule "deps/fifo_map"]
+ path = deps/fifo_map
+ url = git@github.com:nlohmann/fifo_map.git
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj
index 81997ba..a52c38d 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj
+++ b/GlosSIConfig/GlosSIConfig.vcxproj
@@ -68,7 +68,7 @@
/Zc:__cplusplus /Zc:twoPhase- %(AdditionalOptions)
false
NOMINMAX;%(PreprocessorDefinitions)
- ..\deps\WinReg;%(AdditionalIncludeDirectories)
+ ..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)
true
@@ -90,7 +90,7 @@
/Zc:__cplusplus /Zc:zwoPhase- /permissive- %(AdditionalOptions)
false
NOMINMAX;%(PreprocessorDefinitions)
- ..\deps\WinReg;%(AdditionalIncludeDirectories)
+ ..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)
true
@@ -155,7 +155,6 @@
-
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters
index 58136fc..ff925f0 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj.filters
+++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters
@@ -75,9 +75,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -87,6 +84,9 @@
Header Files
+
+ Header Files
+
@@ -100,7 +100,7 @@
- Resource Files
+ Resource Files
\ No newline at end of file
diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc
index 3049894..49f67af 100644
--- a/GlosSIConfig/Resource.rc
+++ b/GlosSIConfig/Resource.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,0,7,1021003100876
- PRODUCTVERSION 0,0,7,1021003100876
+ FILEVERSION 0,0,8,001000606002
+ PRODUCTVERSION 0,0,8,001000606002
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.7.1-21-g31ee876"
+ VALUE "FileVersion", "0.0.8.0-1-gd6c6ef2"
VALUE "InternalName", "GlosSIConfig"
VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSIConfig.exe"
VALUE "ProductName", "GlosSI"
- VALUE "ProductVersion", "0.0.7.1-21-g31ee876"
+ VALUE "ProductVersion", "0.0.8.0-1-gd6c6ef2"
END
END
BLOCK "VarFileInfo"
@@ -308,6 +308,254 @@ IDI_ICON1 ICON "..\GloSC_Icon.ico"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GlosSIConfig/ShortcutsVDF.h b/GlosSIConfig/ShortcutsVDF.h
new file mode 100644
index 0000000..3d03852
--- /dev/null
+++ b/GlosSIConfig/ShortcutsVDF.h
@@ -0,0 +1,493 @@
+/*
+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.cpp b/GlosSIConfig/UIModel.cpp
index a79162b..a1c2451 100644
--- a/GlosSIConfig/UIModel.cpp
+++ b/GlosSIConfig/UIModel.cpp
@@ -141,9 +141,9 @@ void UIModel::deleteTarget(int index)
bool UIModel::isInSteam(QVariant shortcut)
{
const auto map = shortcut.toMap();
- for (auto& steam_shortcut : shortcuts_vdf_.shortcuts) {
- if (map["name"].toString() == QString::fromStdString(steam_shortcut.appName.value)) {
- if (QString::fromStdString(steam_shortcut.exe.value).toLower().contains("glossitarget.exe")) {
+ for (auto& steam_shortcut : shortcuts_vdf_) {
+ if (map["name"].toString() == QString::fromStdString(steam_shortcut.appname)) {
+ if (QString::fromStdString(steam_shortcut.exe).toLower().contains("glossitarget.exe")) {
return true;
}
}
@@ -161,15 +161,13 @@ bool UIModel::addToSteam(QVariant shortcut, const QString& shortcutspath, bool f
const auto launch = map["launch"].toBool();
VDFParser::Shortcut vdfshortcut;
- vdfshortcut.idx = shortcuts_vdf_.shortcuts.size();
- vdfshortcut.appName.value = name.toStdString();
- vdfshortcut.exe.value = ("\"" + appDir.absolutePath() + "/GlosSITarget.exe" + "\"").toStdString();
- vdfshortcut.StartDir.value = (launch && !maybeLaunchPath.isEmpty()
+ vdfshortcut.appname = name.toStdString();
+ vdfshortcut.exe = ("\"" + appDir.absolutePath() + "/GlosSITarget.exe" + "\"").toStdString();
+ vdfshortcut.StartDir = (launch && !maybeLaunchPath.isEmpty()
? (std::string("\"") + std::filesystem::path(maybeLaunchPath.toStdString()).parent_path().string() + "\"")
: ("\"" + appDir.absolutePath() + "\"").toStdString());
- vdfshortcut.appId.value = VDFParser::Parser::calculateAppId(vdfshortcut);
// ShortcutPath; default
- vdfshortcut.LaunchOptions.value = (QString(name).replace(QRegularExpression("[\\\\/:*?\"<>|]"), "") + ".json").toStdString();
+ vdfshortcut.LaunchOptions = (QString(name).replace(QRegularExpression("[\\\\/:*?\"<>|]"), "") + ".json").toStdString();
// IsHidden; default
// AllowDesktopConfig; default
// AllowOverlay; default
@@ -181,25 +179,18 @@ bool UIModel::addToSteam(QVariant shortcut, const QString& shortcutspath, bool f
auto maybeIcon = map["icon"].toString();
if (maybeIcon.isEmpty()) {
if (launch && !maybeLaunchPath.isEmpty())
- vdfshortcut.icon.value =
+ vdfshortcut.icon =
"\"" + (is_windows_ ? QString(maybeLaunchPath).replace(QRegularExpression("\\/"), "\\").toStdString() : maybeLaunchPath.toStdString()) + "\"";
}
else {
- vdfshortcut.icon.value =
+ vdfshortcut.icon =
"\"" + (is_windows_ ? QString(maybeIcon).replace(QRegularExpression("\\/"), "\\").toStdString() : maybeIcon.toStdString()) + "\"";
}
// Add installed locally and GlosSI tag
- VDFParser::ShortcutTag locallyTag;
- locallyTag.idx = 0;
- locallyTag.value = "Installed locally";
- vdfshortcut.tags.value.push_back(locallyTag);
+ vdfshortcut.tags.push_back("Installed locally");
+ vdfshortcut.tags.push_back("GlosSI");
- VDFParser::ShortcutTag glossitag;
- glossitag.idx = 1;
- glossitag.value = "GlosSI";
- vdfshortcut.tags.value.push_back(glossitag);
-
- shortcuts_vdf_.shortcuts.push_back(vdfshortcut);
+ shortcuts_vdf_.push_back(vdfshortcut);
return writeShortcutsVDF(L"add", name.toStdWString(), shortcutspath.toStdWString(), from_cmd);
}
@@ -220,16 +211,10 @@ bool UIModel::addToSteam(const QString& name, const QString& shortcutspath, bool
bool UIModel::removeFromSteam(const QString& name, const QString& shortcutspath, bool from_cmd)
{
qDebug() << "trying to remove " << name << " from steam";
- auto& scuts = shortcuts_vdf_.shortcuts;
- scuts.erase(std::remove_if(scuts.begin(), scuts.end(), [&name](const auto& shortcut) {
- return shortcut.appName.value == name.toStdString();
- }),
- scuts.end());
- for (int i = 0; i < scuts.size(); i++) {
- if (scuts[i].idx != i) {
- scuts[i].idx = i;
- }
- }
+ shortcuts_vdf_.erase(std::ranges::remove_if(shortcuts_vdf_, [&name](const auto& shortcut) {
+ return shortcut.appname == name.toStdString();
+ }).begin(),
+ shortcuts_vdf_.end());
return writeShortcutsVDF(L"remove", name.toStdWString(), shortcutspath.toStdWString(), from_cmd);
}
@@ -271,7 +256,7 @@ bool UIModel::writeShortcutsVDF(const std::wstring& mode, const std::wstring& na
bool write_res;
try {
- write_res = VDFParser::Parser::writeShortcuts(config_path, shortcuts_vdf_);
+ write_res = VDFParser::Parser::writeShortcuts(config_path, shortcuts_vdf_, qDebug());
}
catch (const std::exception& e) {
qDebug() << "Couldn't backup shortcuts file: " << e.what();
@@ -413,7 +398,7 @@ void UIModel::parseShortcutVDF()
{
const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
try {
- shortcuts_vdf_ = VDFParser::Parser::parseShortcuts(config_path);
+ shortcuts_vdf_ = VDFParser::Parser::parseShortcuts(config_path, qDebug());
}
catch (const std::exception& e) {
qDebug() << "Error parsing VDF: " << e.what();
diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h
index 42f8a12..0a2f7d6 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 "VDFParser.h"
+#include "ShortcutsVDF.h"
#include
#include
#include
@@ -74,7 +74,7 @@ class UIModel : public QObject {
QVariantList targets_;
- VDFParser::VDFFile shortcuts_vdf_;
+ std::vector shortcuts_vdf_;
#ifdef _WIN32
bool is_windows_ = true;
diff --git a/GlosSIConfig/VDFParser.h b/GlosSIConfig/VDFParser.h
deleted file mode 100644
index b4c4a93..0000000
--- a/GlosSIConfig/VDFParser.h
+++ /dev/null
@@ -1,593 +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.
-*/
-
-// "Shitty shortcuts.vdf Parser"�
-
-#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-namespace VDFParser {
-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++) {
- 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++) {
- char ch = container.data()[i];
- uint32_t t = (ch ^ crc) & 0xFF;
- crc = (crc >> 8) ^ crc32_table[t];
- }
- return ~crc;
-}
-} // namespace crc
-
-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"};
-
-enum VDFTypeId {
- StringList = 0,
- String,
- Number,
-};
-
-template
-struct VDFKeyPair {
- VDFKeyPair() {}
- explicit VDFKeyPair(type _value) : value(_value) {}
- static constexpr uint8_t _TID = _type_id;
- static constexpr const char* const _KEY = keyname;
- const uint8_t type_id = _TID;
- const char* const key = _KEY;
- type value;
- VDFKeyPair(const VDFKeyPair& other)
- {
- value = other.value;
- };
- VDFKeyPair(VDFKeyPair&& other)
- {
- value = std::move(other.value);
- };
- VDFKeyPair& operator=(const VDFKeyPair& other)
- {
- value = other.value;
- return *this;
- }
- VDFKeyPair& operator=(VDFKeyPair&& other)
- {
- value = std::move(other.value);
- return *this;
- }
-};
-
-struct VDFIdx {
- VDFIdx(){};
- VDFIdx(const VDFIdx& other)
- {
- data = other.data;
- };
- VDFIdx(VDFIdx&& other)
- {
- data = std::move(other.data);
- };
- VDFIdx(int idx)
- {
- data = std::to_string(idx);
- }
- std::string data;
- operator int() const
- {
- int res = 0;
- std::from_chars(data.data(), data.data() + data.size(), res);
- return res;
- }
-
- VDFIdx& operator=(const VDFIdx& other)
- {
- data = other.data;
-
- return *this;
- }
- VDFIdx& operator=(VDFIdx&& other)
- {
- data = std::move(other.data);
- return *this;
- }
-};
-
-struct ShortcutTag {
- ShortcutTag(){};
- ShortcutTag(const ShortcutTag& other)
- {
- idx = other.idx;
- value = other.value;
- };
- ShortcutTag(ShortcutTag&& other)
- {
- idx = std::move(other.idx);
- value = std::move(other.value);
- };
- VDFIdx idx;
- std::string value;
- const uint16_t end_marker = 0x0808;
-
- ShortcutTag& operator=(const ShortcutTag& other)
- {
- idx = other.idx;
- value = other.value;
- return *this;
- }
- ShortcutTag& operator=(ShortcutTag&& other)
- {
- idx = std::move(other.idx);
- value = std::move(other.value);
- return *this;
- }
-};
-
-struct Shortcut {
- VDFIdx idx;
- VDFKeyPair appId{0x000000};
- VDFKeyPair appName{""};
- VDFKeyPair exe{"\"\""}; // Qouted
- VDFKeyPair StartDir{"\"\""}; // Qouted
- VDFKeyPair icon{""}; // Qouted or empty
- VDFKeyPair ShortcutPath{""}; // Qouted or empty?
- VDFKeyPair LaunchOptions{""}; // UNQOUTED or empty
- VDFKeyPair IsHidden{0};
- VDFKeyPair AllowDesktopConfig{1};
- VDFKeyPair AllowOverlay{1};
- VDFKeyPair openvr{0};
- VDFKeyPair Devkit{0};
- VDFKeyPair DevkitGameID{""};
- VDFKeyPair DevkitOverrideAppID{0}; //
- VDFKeyPair LastPlayTime{0}; //
- VDFKeyPair FlatpakAppID{""}; //
- VDFKeyPair, VDFTypeId::StringList> tags{};
- Shortcut& operator=(const Shortcut& other)
- {
- idx = other.idx;
- appId = other.appId;
- appName = other.appName;
- exe = other.exe;
- StartDir = other.StartDir;
- icon = other.icon;
- ShortcutPath = other.ShortcutPath;
- LaunchOptions = other.LaunchOptions;
- LaunchOptions = other.LaunchOptions;
- IsHidden = other.IsHidden;
- AllowDesktopConfig = other.AllowDesktopConfig;
- AllowOverlay = other.AllowOverlay;
- openvr = other.openvr;
- Devkit = other.Devkit;
- DevkitGameID = other.DevkitGameID;
- DevkitOverrideAppID = other.DevkitOverrideAppID;
- LastPlayTime = other.LastPlayTime;
- FlatpakAppID = other.FlatpakAppID;
- tags = other.tags;
- return *this;
- }
- //std::wstring to_json()
- //{
- // std::wstring res = L"{";
- // res += L"idx: " + std::to_wstring(idx.operator int()) + L",\n";
- // res += L"appId: " + std::to_wstring(appId.value) + L",\n";
- // res += L"appName: " + std::filesystem::path(appName.value).wstring() + L",\n";
- // res += L"StartDir: " + std::filesystem::path(StartDir.value).wstring() + L",\n";
- // res += L"ShortcutPath: " + std::filesystem::path(ShortcutPath.value).wstring() + L",\n";
- // res += L"LaunchOptions: " + std::filesystem::path(LaunchOptions.value).wstring() + L",\n";
- // res += L"IsHidden: " + (IsHidden.value ? L"true" : L"false") + L",\n";
- // res += L"AllowDesktopConfig: " + (AllowDesktopConfig.value ? L"true" : L"false") + L",\n";
- // res += L"idx: " + std::to_wstring(appId.value) + L",\n";
- // res += L"}";
- // return res;
- //}
-};
-
-struct VDFFile {
- VDFFile(){};
- VDFFile(const VDFFile& other)
- {
- shortcuts = other.shortcuts;
- };
- VDFFile(VDFFile&& other)
- {
- shortcuts = std::move(other.shortcuts);
- };
- const uint8_t first_byte = 0x00;
- const std::string identifier = "shortcuts";
- std::vector shortcuts;
- const uint16_t end_marker = 0x0808;
- VDFFile& operator=(const VDFFile& other)
- {
- shortcuts = other.shortcuts;
- return *this;
- }
- VDFFile& operator=(VDFFile&& other)
- {
- shortcuts = std::move(other.shortcuts);
- return *this;
- }
- //std::wstring to_json()
- //{
- // std::wstring res = L"[";
-
- // res += L"]";
- // return res;
- //}
-};
-
-class Parser {
- private:
- static inline std::ifstream ifile;
- static inline std::ofstream ofile;
-
- template
- static inline auto readVDFBuffer(typ* buff, size sz)
- {
- if (ifile.eof()) {
-
- return;
- }
- ifile.read((char*)buff, sz);
- }
-
- template
- static inline auto readVDFValue()
- {
- uint8_t buff[sizeof(typ)];
- ifile.read((char*)buff, sizeof(typ));
- return *reinterpret_cast(buff);
- }
-
- static inline std::string readVDFString()
- {
- 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;
- }
-
- public:
- static inline uint32_t calculateAppId(const Shortcut& shortcut)
- {
- std::string buff = shortcut.exe.value + shortcut.appName.value;
- auto checksum = crc::calculate_crc(buff);
- return checksum | 0x80000000;
- }
-
- static inline VDFFile parseShortcuts(std::filesystem::path path)
- {
- VDFFile vdffile;
-
- ifile.open(path, std::ios::binary | std::ios::in);
- if (!ifile.is_open()) {
- return {};
- }
-
- auto firsty = readVDFValue();
- if (vdffile.first_byte != firsty) {
- // TODO: invalid
- ifile.close();
- throw std::exception("First byte is invalid in vdf");
- }
-
- auto headername = readVDFString();
- if (vdffile.identifier != headername) {
- // TODO: invalid
- ifile.close();
- throw std::exception("VDF header is invalid");
- }
-
- while (true) {
- std::vector buff;
- if (ifile.eof()) {
- break;
- }
- char b = '\x0';
- readVDFBuffer(&b, 1); // skip 0 byte
- Shortcut shortcut;
- shortcut.idx.data = readVDFString();
- if (shortcut.idx.data == "\x08\x08") {
- break;
- }
- while (true) // TODO;
- {
- if (ifile.eof()) {
- break;
- }
- const auto tid = static_cast(readVDFValue());
- if (tid == 0x08) {
- auto nextbyte = readVDFValue();
- if (nextbyte == 0x08) {
- break;
- }
- else {
- // WTF?!
- // TODO:
- throw std::exception("VDF: WTF");
- }
- }
- auto key = readVDFString();
- if ((tid == 0x08 && key[0] == 0x08) || key == "\x08\x08") {
- break;
- }
- if (key == shortcut.appId.key) {
- shortcut.appId.value = readVDFValue();
- continue;
- }
- if (key == shortcut.appName.key) {
- shortcut.appName.value = readVDFString();
- continue;
- }
- if (key == shortcut.exe.key) {
- shortcut.exe.value = readVDFString();
- continue;
- }
- if (key == shortcut.StartDir.key) {
- shortcut.StartDir.value = readVDFString();
- continue;
- }
- if (key == shortcut.icon.key) {
- shortcut.icon.value = readVDFString();
- continue;
- }
- if (key == shortcut.ShortcutPath.key) {
- shortcut.ShortcutPath.value = readVDFString();
- continue;
- }
- if (key == shortcut.LaunchOptions.key) {
- shortcut.LaunchOptions.value = readVDFString();
- continue;
- }
- if (key == shortcut.IsHidden.key) {
- shortcut.IsHidden.value = readVDFValue();
- continue;
- }
- if (key == shortcut.AllowDesktopConfig.key) {
- shortcut.AllowDesktopConfig.value = readVDFValue();
- continue;
- }
- if (key == shortcut.AllowOverlay.key) {
- shortcut.AllowOverlay.value = readVDFValue();
- continue;
- }
- if (key == shortcut.openvr.key) {
- shortcut.openvr.value = readVDFValue();
- continue;
- }
- if (key == shortcut.Devkit.key) {
- shortcut.Devkit.value = readVDFValue();
- continue;
- }
- if (key == shortcut.DevkitGameID.key) {
- shortcut.DevkitGameID.value = readVDFString();
- continue;
- }
- if (key == shortcut.DevkitOverrideAppID.key) {
- shortcut.DevkitOverrideAppID.value = readVDFValue();
- continue;
- }
- if (key == shortcut.LastPlayTime.key) {
- shortcut.LastPlayTime.value = readVDFValue();
- continue;
- }
- if (key == shortcut.FlatpakAppID.key) {
- shortcut.FlatpakAppID.value = readVDFString();
- continue;
- }
- if (key == shortcut.tags.key) {
- ShortcutTag tag;
- while (true) {
- if (ifile.eof()) {
- break;
- }
- char tbuff[2];
- readVDFBuffer(tbuff, 2); // 2 bytes POSSIBLE end marker
- ifile.seekg(-1, std::ios_base::cur); // go one back, skip typeId
- if (tbuff[0] == 0x08 && tbuff[1] == 0x08) {
- ifile.seekg(-1, std::ios_base::cur); // another back
- break;
- }
- tag.idx.data = readVDFString();
- if (tag.idx.data == "\x08\x08") {
- ifile.seekg(-2, std::ios_base::cur);
- break;
- }
- tag.value = readVDFString();
- shortcut.tags.value.push_back(tag);
- }
- continue;
- }
- }
- if (!(shortcut.idx.data == "\x00\x00")) {
- vdffile.shortcuts.push_back(shortcut);
- }
- }
-
- ifile.close();
-
- return vdffile;
- }
-
- static inline bool writeShortcuts(std::filesystem::path path, const VDFFile& vdffile)
- {
- const auto backupFileName = path.wstring() + L".bak";
- if (std::filesystem::exists(path) && !std::filesystem::exists(backupFileName)) {
- qDebug() << "No shortcuts backup detected... Creating now...";
- const auto copied = std::filesystem::copy_file(path, backupFileName, std::filesystem::copy_options::update_existing);
- if (!copied) {
- qDebug() << "failed to copy shortcuts.vdf to backup!";
- }
- }
-
- ofile.open(path.wstring(), std::ios::binary | std::ios::out);
- if (!ofile.is_open()) {
- return false;
- }
- ofile.write((char*)&vdffile.first_byte, 1);
- ofile.write(vdffile.identifier.data(), vdffile.identifier.length());
- ofile.write("\x00", 1);
- for (auto& shortcut : vdffile.shortcuts) {
- ofile.write("\x00", 1);
- ofile.write(shortcut.idx.data.data(), shortcut.idx.data.length());
- ofile.write("\x00", 1);
- //
- ofile.write((char*)&shortcut.appId.type_id, 1);
- ofile.write(shortcut.appId.key, 6);
- ofile.write((char*)&shortcut.appId.value, 4);
-
- //
- ofile.write((char*)&shortcut.appName.type_id, 1);
- ofile.write(shortcut.appName.key, 8);
- ofile.write(shortcut.appName.value.data(), shortcut.appName.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.exe.type_id, 1);
- ofile.write(shortcut.exe.key, 4);
- ofile.write(shortcut.exe.value.data(), shortcut.exe.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.StartDir.type_id, 1);
- ofile.write(shortcut.StartDir.key, 9);
- ofile.write(shortcut.StartDir.value.data(), shortcut.StartDir.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.icon.type_id, 1);
- ofile.write(shortcut.icon.key, 5);
- ofile.write(shortcut.icon.value.data(), shortcut.icon.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.ShortcutPath.type_id, 1);
- ofile.write(shortcut.ShortcutPath.key, 13);
- ofile.write(shortcut.ShortcutPath.value.data(), shortcut.ShortcutPath.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.LaunchOptions.type_id, 1);
- ofile.write(shortcut.LaunchOptions.key, 14);
- ofile.write(shortcut.LaunchOptions.value.data(), shortcut.LaunchOptions.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.IsHidden.type_id, 1);
- ofile.write(shortcut.IsHidden.key, 9);
- ofile.write((char*)&shortcut.IsHidden.value, 4);
-
- //
- ofile.write((char*)&shortcut.AllowDesktopConfig.type_id, 1);
- ofile.write(shortcut.AllowDesktopConfig.key, 19);
- ofile.write((char*)&shortcut.AllowDesktopConfig.value, 4);
-
- //
- ofile.write((char*)&shortcut.AllowOverlay.type_id, 1);
- ofile.write(shortcut.AllowOverlay.key, 13);
- ofile.write((char*)&shortcut.AllowOverlay.value, 4);
-
- //
- ofile.write((char*)&shortcut.openvr.type_id, 1);
- ofile.write(shortcut.openvr.key, 7);
- ofile.write((char*)&shortcut.openvr.value, 4);
-
- //
- ofile.write((char*)&shortcut.Devkit.type_id, 1);
- ofile.write(shortcut.Devkit.key, 7);
- ofile.write((char*)&shortcut.Devkit.value, 4);
-
- //
- ofile.write((char*)&shortcut.DevkitGameID.type_id, 1);
- ofile.write(shortcut.DevkitGameID.key, 13);
- ofile.write(shortcut.DevkitGameID.value.data(), shortcut.DevkitGameID.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.DevkitOverrideAppID.type_id, 1);
- ofile.write(shortcut.DevkitOverrideAppID.key, 20);
- ofile.write((char*)&shortcut.DevkitOverrideAppID.value, 4);
-
- //
- ofile.write((char*)&shortcut.LastPlayTime.type_id, 1);
- ofile.write(shortcut.LastPlayTime.key, 13);
- ofile.write((char*)&shortcut.LastPlayTime.value, 4);
-
- //
- ofile.write((char*)&shortcut.FlatpakAppID.type_id, 1);
- ofile.write(shortcut.FlatpakAppID.key, 13);
- ofile.write(shortcut.FlatpakAppID.value.data(), shortcut.FlatpakAppID.value.length());
- ofile.write("\x00", 1);
-
- //
- ofile.write((char*)&shortcut.tags.type_id, 1);
- ofile.write(shortcut.tags.key, 5);
- for (auto& tag : shortcut.tags.value) {
- ofile.write(tag.idx.data.data(), tag.idx.data.length());
- ofile.write("\x00", 1);
- ofile.write(tag.value.data(), tag.value.length());
- ofile.write("\x00", 1);
- }
- ofile.write("\x08\x08", 2);
- }
- ofile.write("\x08\x08", 2);
- ofile.close();
- return true;
- }
-};
-} // namespace VDFParser
diff --git a/deps/fifo_map b/deps/fifo_map
new file mode 160000
index 0000000..d732aaf
--- /dev/null
+++ b/deps/fifo_map
@@ -0,0 +1 @@
+Subproject commit d732aaf9a315415ae8fd7eb11e3a4c1f80e42a48