eden-miror/src/common/fs/ryujinx_compat.cpp
crueter 08f3639c80
[desktop, fs] main_window separation; fix Ryujinx save data link issues (#2929)
Some genius decided to put the entire MainWindow class into main.h and
main.cpp, which is not only horrific practice but also completely
destroys clangd beyond repair. Please, just don't do this.

(this will probably merge conflict to hell and back)

Also, fixes a bunch of issues with Ryujinx save data link:
- Paths with spaces would cause mklink to fail
- Add support for portable directories
- Symlink detection was incorrect sometimes(????)
- Some other stuff I'm forgetting

Furthermore, when selecting "From Eden" and attempting to save in Ryujinx, Ryujinx would destroy the link for... some reason? So to get around this we just copy the Eden data to Ryujinx then treat it like a "From Ryujinx" op

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2929
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2025-11-09 18:07:38 +01:00

106 lines
2.8 KiB
C++

// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "ryujinx_compat.h"
#include "common/fs/path_util.h"
#include <cstddef>
#include <cstring>
#include <fmt/ranges.h>
#include <fstream>
namespace Common::FS {
namespace fs = std::filesystem;
fs::path GetKvdbPath()
{
return GetKvdbPath(GetLegacyPath(EmuPath::RyujinxDir));
}
fs::path GetKvdbPath(const fs::path& path) {
return path / "bis" / "system" / "save" / "8000000000000000" / "0"
/ "imkvdb.arc";
}
fs::path GetRyuPathFromSavePath(const fs::path& path) {
// This is a horrible hack, but I cba to find something better
return path.parent_path().parent_path().parent_path().parent_path().parent_path();
}
fs::path GetRyuSavePath(const u64 &save_id)
{
return GetRyuSavePath(GetLegacyPath(EmuPath::RyujinxDir), save_id);
}
std::filesystem::path GetRyuSavePath(const std::filesystem::path& path, const u64& save_id) {
std::string hex = fmt::format("{:016x}", save_id);
// TODO: what's the difference between 0 and 1?
return path / "bis" / "user" / "save" / hex / "0";
}
IMENReadResult ReadKvdb(const fs::path &path, std::vector<IMEN> &imens)
{
std::ifstream kvdb{path, std::ios::binary | std::ios::ate};
if (!kvdb) {
return IMENReadResult::Nonexistent;
}
size_t file_size = kvdb.tellg();
// IMKV header + 8 bytes
if (file_size < 0xB) {
return IMENReadResult::NoHeader;
}
// magic (not the wizard kind)
kvdb.seekg(0, std::ios::beg);
char header[12];
kvdb.read(header, 12);
if (std::memcmp(header, IMKV_MAGIC, 4) != 0) {
return IMENReadResult::InvalidMagic;
}
// calculate num. of imens left
std::size_t remaining = (file_size - 12);
std::size_t num_imens = remaining / IMEN_SIZE;
// File is misaligned and probably corrupt (rip)
if (remaining % IMEN_SIZE != 0) {
return IMENReadResult::Misaligned;
}
// if there aren't any IMENs, it's empty and we can safely no-op out of here
if (num_imens == 0) {
return IMENReadResult::NoImens;
}
imens.reserve(num_imens);
// initially I wanted to do a struct, but imkvdb is 140 bytes
// while the compiler will murder you if you try to align u64 to 4 bytes
for (std::size_t i = 0; i < num_imens; ++i) {
char magic[4];
u64 title_id = 0;
u64 save_id = 0;
kvdb.read(magic, 4);
if (std::memcmp(magic, IMEN_MAGIC, 4) != 0) {
return IMENReadResult::InvalidMagic;
}
kvdb.ignore(0x8);
kvdb.read(reinterpret_cast<char *>(&title_id), 8);
kvdb.ignore(0x38);
kvdb.read(reinterpret_cast<char *>(&save_id), 8);
kvdb.ignore(0x38);
imens.emplace_back(IMEN{title_id, save_id});
}
return IMENReadResult::Success;
}
} // namespace Common::FS