Use shrotcuts_parser from submodule

pull/175/head
Peter Repukat 2 years ago
parent 288bba1436
commit 1ca127519a

3
.gitmodules vendored

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

@ -68,7 +68,7 @@
<AdditionalOptions>/Zc:__cplusplus /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<CompileAsWinRT>false</CompileAsWinRT>
<PreprocessorDefinitions>NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Manifest>
<EnableDpiAwareness>true</EnableDpiAwareness>
@ -90,7 +90,7 @@
<AdditionalOptions>/Zc:__cplusplus /Zc:zwoPhase- /permissive- %(AdditionalOptions)</AdditionalOptions>
<CompileAsWinRT>false</CompileAsWinRT>
<PreprocessorDefinitions>NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\deps\WinReg;..\deps\fifo_map\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Manifest>
<EnableDpiAwareness>true</EnableDpiAwareness>
@ -153,7 +153,6 @@
<ItemGroup>
<ClInclude Include="ExeImageProvider.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="ShortcutsVDF.h" />
<ClInclude Include="UWPFetch.h" />
<ClInclude Include="WinEventFilter.h" />
</ItemGroup>

@ -84,9 +84,6 @@
<ClInclude Include="ExeImageProvider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ShortcutsVDF.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Xml Include="manifest.xml">

@ -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"

@ -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 <any>
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <fstream>
#include <regex>
#include <ranges>
#include <fifo_map.hpp>
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 <typename CONT>
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<std::string> 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<uint32_t>(value));
case String:
return "\"" + std::regex_replace(std::regex_replace(std::any_cast<std::string>(value), std::regex(R"(\\)"), R"(\\)"), std::regex(R"(")"), R"(\")") + "\"";
case Map: {
const auto& map = std::any_cast<nlohmann::fifo_map<std::string, VDFValue>>(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<std::string, VDFValue> 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<std::string> tags;
nlohmann::fifo_map<std::string, VDFValue> unsupported_keys;
Shortcut() = default;
explicit Shortcut(const nlohmann::fifo_map<std::string, VDFValue>& 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<uint32_t>(value.value);
break;
case internal::str2int(k_IsHidden):
IsHidden = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_AllowDesktopConfig):
AllowDesktopConfig = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_AllowOverlay):
AllowOverlay = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_openvr):
openvr = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_Devkit):
Devkit = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_DevkitOverrideAppID):
DevkitOverrideAppID = std::any_cast<uint32_t>(value.value);
break;
case internal::str2int(k_LastPlayTime):
LastPlayTime = std::any_cast<uint32_t>(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<std::string>(value.value);
break;
case internal::str2int(k_exe):
exe = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_StartDir):
StartDir = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_icon):
icon = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_ShortcutPath):
ShortcutPath = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_LaunchOptions):
LaunchOptions = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_DevkitGameID):
DevkitGameID = std::any_cast<std::string>(value.value);
break;
case internal::str2int(k_FlatpakAppID):
FlatpakAppID = std::any_cast<std::string>(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<nlohmann::fifo_map<std::string, VDFValue>>(value.value) | std::views::values) {
if (type == String) {
tags.push_back(std::any_cast<std::string>(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<std::string, VDFValue> 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<std::string, VDFValue> 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 <typename typ>
static inline auto readVDFValue()
{
uint8_t buff[sizeof(typ)];
ifile.read((char*)buff, sizeof(typ));
return *reinterpret_cast<typ*>(buff);
}
template <>
static inline auto readVDFValue<std::string>()
{
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<nlohmann::fifo_map<std::string, VDFValue>>()
{
auto res = nlohmann::fifo_map<std::string, VDFValue>();
while (true) {
const auto& [key, value] = readVDFValue();
if (value.type == EndMarker) {
return res;
}
res[key] = value;
}
}
static inline std::pair<std::string, VDFValue> readVDFValue()
{
auto res = std::pair<std::string, VDFValue>("", VDFValue(EndMarker, nullptr));
if (ifile.eof()) {
return res;
}
const auto tid = static_cast<VDFTypeId>(readVDFValue<uint8_t>());
if (tid == EndMarker) {
return res;
}
res.second.type = tid;
res.first = readVDFValue<std::string>();
switch (tid) {
case VDFTypeId::Map:
res.second.value = readVDFValue<nlohmann::fifo_map<std::string, VDFValue>>();
break;
case VDFTypeId::Number:
res.second.value = readVDFValue<uint32_t>();
break;
case VDFTypeId::String:
res.second.value = readVDFValue<std::string>();
break;
default:
throw std::exception("VDF: Unknown TypeID");
break;
}
return res;
}
template <typename typ>
static inline auto writeVDFValue(typ v)
{
ofile.write((char*)&v, sizeof(typ));
}
template <>
static inline auto writeVDFValue<std::string>(std::string v)
{
ofile.write(v.data(), v.length());
ofile.write("\x00", 1);
}
template <>
static inline auto writeVDFValue<nlohmann::fifo_map<std::string, VDFValue>>(nlohmann::fifo_map<std::string, VDFValue> v)
{
for (const auto& pair : v) {
writeVDFValue(pair);
}
ofile.write("\x08", 1);
}
static inline void writeVDFValue(const std::pair<const std::string, VDFValue>& value)
{
ofile.write((char*)(&value.second.type), 1);
writeVDFValue(value.first);
switch (value.second.type) {
case Map:
writeVDFValue(std::any_cast<nlohmann::fifo_map<std::string, VDFValue>>(value.second.value));
break;
case Number:
writeVDFValue(std::any_cast<uint32_t>(value.second.value));
break;
case String:
writeVDFValue(std::any_cast<std::string>(value.second.value));
break;
default:
throw std::exception("VDF: Unknown TypeID");
break;
}
}
public:
template <typename LogStream = std::ostream>
static inline std::vector<Shortcut> 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<nlohmann::fifo_map<std::string, VDFValue>>(shortcutsVDF.second.value);
std::vector<Shortcut> 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<nlohmann::fifo_map<std::string, VDFValue>>(sc));
}
return shortcuts;
}
template <typename LogStream = std::ostream>
static inline bool writeShortcuts(const std::filesystem::path& path, const std::vector<Shortcut>& 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<std::string, VDFValue> 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

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include "ShortcutsVDF.h"
#include <shortcuts_vdf.hpp>
#include <QJsonObject>
#include <QObject>
#include <QVariant>

@ -0,0 +1 @@
Subproject commit 2816b31c8e777c2920e1f0881ce10c5c66e30c63
Loading…
Cancel
Save