From ed1fb12ae47b44d45d98e4a99c90635d7b3cf54b Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Wed, 27 Oct 2021 15:43:59 +0200 Subject: [PATCH] =?UTF-8?q?"Shitty=20shortcuts.vdf=20Parser"=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...In search of motivation >.< --- GlosSIConfig/VDFParser.h | 491 ++++++++++++++++++++++++++++++++++----- 1 file changed, 431 insertions(+), 60 deletions(-) diff --git a/GlosSIConfig/VDFParser.h b/GlosSIConfig/VDFParser.h index a86a640..3bdaec6 100644 --- a/GlosSIConfig/VDFParser.h +++ b/GlosSIConfig/VDFParser.h @@ -13,15 +13,47 @@ 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 +#include +#include namespace VDFParser { - static constexpr const char k_appId[] = { "appId" }; + 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; + } + } + + 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" }; @@ -38,6 +70,13 @@ namespace VDFParser static constexpr const char k_LastPlayTime[] = { "LastPlayTime" }; static constexpr const char k_tags[] = { "tags" }; + enum VDFTypeId + { + StringList = 0, + String, + Number, + }; + template struct VDFKeyPair { @@ -50,88 +89,420 @@ namespace VDFParser type value; }; - static constexpr uint32_t idx_begin_ = 0x30; - struct ShortcutTags + template + struct VDFIdx { - const char idx[2] = "0"; - std::vector tags; + VDFIdx() {}; + VDFIdx(int idx) + { + if (idx > 99) + { + data[0] = initialByte; + data[1] = 0; + } + else if (idx < 10) + { + data[1] = std::to_string(idx).c_str()[0]; + } + else + { + auto meh = std::to_string(idx).c_str(); + data[0] = meh[0] + initialByte; + data[1] = meh[1]; + } + } + char data[2] = { initialByte, 0x0 }; + operator int() const { + if (data[0] == initialByte) + { + int res = 0; + std::from_chars(&data[1], &data[1], res); + return res; + } + int res = 0; + data[0] -= initialByte; + std::from_chars(&data[0], &data[1], res); + data[0] += initialByte; + return res; + } + }; + + struct ShortcutTag + { + VDFIdx<0x01> idx; // I Hope this is how it works... See VDFIdx + std::string value; const uint16_t end_marker = 0x0808; }; struct Shortcut { - const char idx[2] = "0"; - VDFKeyPair appId{ 0x000000 }; // TODO ??? - 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 tags{ }; + VDFIdx<0x00> 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, VDFTypeId::StringList> tags{ }; }; struct VDFFile { const uint8_t first_byte = 0x00; - const char* const identifier = "shortcuts"; - std::vector shortcuts; // only use data... + const std::string identifier = "shortcuts"; + std::vector shortcuts; const uint16_t end_marker = 0x0808; }; - 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 QList parseShortcuts(std::filesystem::path path) + 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; - vdffile.shortcuts.emplace_back(); - vdffile.shortcuts[0].tags.value.tags.emplace_back(); - QList res; + ifile.open(path.string(), std::ios::binary | std::ios::in); + if (!ifile.is_open()) + { + return {}; + } + + auto firsty = readVDFValue(); + if (vdffile.first_byte != firsty) + { + // TODO: invalid + ifile.close(); + return vdffile; + } - QFile shortcuts_file(QString::fromStdWString(path.wstring())); - if (!shortcuts_file.open(QFile::ReadWrite)) + auto headername = readVDFString(); + if (vdffile.identifier != headername) { - // TODO: try to create file... - return res; + // TODO: invalid + ifile.close(); + return vdffile; } - //const QByteArray content = shortcuts_file.readAll(); - //const QByteArray header = QByteArray(content.data(), 11); - //if (file_header.compare(header) != 0) - //{ - // // TODO: invalid header - //} - shortcuts_file.close(); - return res; + char buff[3]; + while(true) + { + if (ifile.eof()) + { + break; + } + readVDFBuffer(buff, 3); // 2 bytes idx, 0x00 delmiter + if (buff[0] == 0x08 && buff[1] == 0x08) + { + break; + } + Shortcut shortcut; + shortcut.idx.data[0] = buff[0]; shortcut.idx.data[1] = buff[1]; + while (true) // TODO; + { + if (ifile.eof()) + { + break; + } + VDFTypeId tid = static_cast(readVDFValue()); + if (tid == 0x08) + { + auto nextbyte = readVDFValue(); + if (nextbyte == 0x08) + { + break; + } else { + // WTF?! + // TODO: + throw std::exception("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.tags.key) + { + // TODO: read tags + ShortcutTag tag; + while (true) + { + if (ifile.eof()) + { + break; + } + char tbuff[2]; + readVDFBuffer(tbuff, 2); // 2 bytes idx + if (tbuff[0] == 0x08 && tbuff[1] == 0x08) + { + ifile.seekg(-2, std::ios_base::cur); + break; + } + tag.idx.data[0] = tbuff[0]; tag.idx.data[1] = tbuff[1]; + ifile.seekg(1, std::ios_base::cur); + tag.value = readVDFString(); + shortcut.tags.value.push_back(tag); + } + continue; + } + + } + if (!(shortcut.idx.data[0] == 0x0 && shortcut.idx.data[1] == 0x0)) + { + vdffile.shortcuts.push_back(shortcut); + } + } + + ifile.close(); + + return vdffile; + } + + static inline bool writeShortcuts(std::filesystem::path path, const VDFFile& vdffile) + { + ofile.open(path.string(), 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(shortcut.idx.data, 2); + 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.tags.type_id, 1); + ofile.write(shortcut.tags.key, 5); + for (auto& tag : shortcut.tags.value) + { + ofile.write(tag.idx.data, 2); + 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; } + }; } - -//AppName = app.Name, -//Exe = exePath, -//StartDir = exeDir, -//LaunchOptions = app.Aumid, -//AllowDesktopConfig = 1, -//AllowOverlay = 1, -//Icon = app.Icon, -//Index = shortcuts.Length, -//IsHidden = 0, -//OpenVR = 0, -//ShortcutPath = "", -//Tags = tags, -//Devkit = 0, -//DevkitGameID = "", -//LastPlayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), \ No newline at end of file