"Shitty shortcuts.vdf Parser"™

...In search of motivation >.<
pull/130/head
Peter Repukat 3 years ago
parent 0a2d043400
commit ed1fb12ae4

@ -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"<22>
#pragma once
#include <filesystem>
#include <QString>
#include <QVariant>
#include <QList>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <charconv>
namespace VDFParser
{
static constexpr const char k_appId[] = { "appId" };
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++) {
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<const char* const keyname, typename type, const uint8_t const _type_id>
struct VDFKeyPair
{
@ -50,88 +89,420 @@ namespace VDFParser
type value;
};
static constexpr uint32_t idx_begin_ = 0x30;
struct ShortcutTags
template<uint8_t initialByte>
struct VDFIdx
{
const char idx[2] = "0";
std::vector<const char*> 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<k_appId, uint32_t, 0x02> appId{ 0x000000 }; // TODO ???
VDFKeyPair<k_appname, const char*, 0x01> appName{ "" };
VDFKeyPair<k_exe, const char*, 0x01> exe{ "\"\"" }; // Qouted
VDFKeyPair<k_StartDir, const char*, 0x01> StartDir{ "\"\"" }; // Qouted
VDFKeyPair<k_icon, const char*, 0x01> icon{ "" }; // Qouted or empty
VDFKeyPair<k_ShortcutPath, const char*, 0x01> ShortcutPath{ "" }; // Qouted or empty?
VDFKeyPair<k_LaunchOptions, const char*, 0x01> LaunchOptions{ "" }; // UNQOUTED or empty
VDFKeyPair<k_IsHidden, uint32_t, 0x02> IsHidden{ 0 };
VDFKeyPair<k_AllowDesktopConfig, uint32_t, 0x02> AllowDesktopConfig{ 1 };
VDFKeyPair<k_AllowOverlay, uint32_t, 0x02> AllowOverlay{ 1 };
VDFKeyPair<k_openvr, uint32_t, 0x02> openvr{ 0 };
VDFKeyPair<k_Devkit, uint32_t, 0x02> Devkit{ 0 };
VDFKeyPair<k_DevkitGameID, const char*, 0x01> DevkitGameID{ "" };
VDFKeyPair<k_DevkitOverrideAppID, uint32_t, 0x02> DevkitOverrideAppID{ 0 }; //
VDFKeyPair<k_LastPlayTime, uint32_t, 0x02> LastPlayTime{ 0 }; //
VDFKeyPair<k_tags, ShortcutTags, 0x00> tags{ };
VDFIdx<0x00> idx;
VDFKeyPair<k_appid, uint32_t, VDFTypeId::Number> appId{ 0x000000 };
VDFKeyPair<k_appname, std::string, VDFTypeId::String> appName{ "" };
VDFKeyPair<k_exe, std::string, VDFTypeId::String> exe{ "\"\"" }; // Qouted
VDFKeyPair<k_StartDir, std::string, VDFTypeId::String> StartDir{ "\"\"" }; // Qouted
VDFKeyPair<k_icon, std::string, VDFTypeId::String> icon{ "" }; // Qouted or empty
VDFKeyPair<k_ShortcutPath, std::string, VDFTypeId::String> ShortcutPath{ "" }; // Qouted or empty?
VDFKeyPair<k_LaunchOptions, std::string, VDFTypeId::String> LaunchOptions{ "" }; // UNQOUTED or empty
VDFKeyPair<k_IsHidden, uint32_t, VDFTypeId::Number> IsHidden{ 0 };
VDFKeyPair<k_AllowDesktopConfig, uint32_t, VDFTypeId::Number> AllowDesktopConfig{ 1 };
VDFKeyPair<k_AllowOverlay, uint32_t, VDFTypeId::Number> AllowOverlay{ 1 };
VDFKeyPair<k_openvr, uint32_t, VDFTypeId::Number> openvr{ 0 };
VDFKeyPair<k_Devkit, uint32_t, VDFTypeId::Number> Devkit{ 0 };
VDFKeyPair<k_DevkitGameID, std::string, VDFTypeId::String> DevkitGameID{ "" };
VDFKeyPair<k_DevkitOverrideAppID, uint32_t, VDFTypeId::Number> DevkitOverrideAppID{ 0 }; //
VDFKeyPair<k_LastPlayTime, uint32_t, VDFTypeId::Number> LastPlayTime{ 0 }; //
VDFKeyPair<k_tags, std::vector<ShortcutTag>, VDFTypeId::StringList> tags{ };
};
struct VDFFile
{
const uint8_t first_byte = 0x00;
const char* const identifier = "shortcuts";
std::vector<Shortcut> shortcuts; // only use data...
const std::string identifier = "shortcuts";
std::vector<Shortcut> shortcuts;
const uint16_t end_marker = 0x0808;
};
class Parser
{
private:
static inline std::ifstream ifile;
static inline std::ofstream ofile;
template<typename typ, typename size>
static inline auto readVDFBuffer(typ& buff,size sz)
{
if (ifile.eof())
{
return;
}
ifile.read((char*)buff, sz);
}
template<typename typ>
static inline auto readVDFValue()
{
uint8_t buff[sizeof(typ)];
ifile.read((char*)buff, sizeof(typ));
return *reinterpret_cast<typ*>(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<QVariantMap> 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<QVariantMap> res;
ifile.open(path.string(), std::ios::binary | std::ios::in);
if (!ifile.is_open())
{
return {};
}
auto firsty = readVDFValue<uint8_t>();
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<VDFTypeId>(readVDFValue<uint8_t>());
if (tid == 0x08)
{
auto nextbyte = readVDFValue<uint8_t>();
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<uint32_t>();
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<uint32_t>();
continue;
}
if (key == shortcut.AllowDesktopConfig.key)
{
shortcut.AllowDesktopConfig.value = readVDFValue<uint32_t>();
continue;
}
if (key == shortcut.AllowOverlay.key)
{
shortcut.AllowOverlay.value = readVDFValue<uint32_t>();
continue;
}
if (key == shortcut.openvr.key)
{
shortcut.openvr.value = readVDFValue<uint32_t>();
continue;
}
if (key == shortcut.Devkit.key)
{
shortcut.Devkit.value = readVDFValue<uint32_t>();
continue;
}
if (key == shortcut.DevkitGameID.key)
{
shortcut.DevkitGameID.value = readVDFString();
continue;
}
if (key == shortcut.DevkitOverrideAppID.key)
{
shortcut.DevkitOverrideAppID.value = readVDFValue<uint32_t>();
continue;
}
if (key == shortcut.LastPlayTime.key)
{
shortcut.LastPlayTime.value = readVDFValue<uint32_t>();
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(),
Loading…
Cancel
Save