aboutsummaryrefslogtreecommitdiff
path: root/src/common/fs/ryujinx_compat.cpp
blob: 610ba736a7746a10ea0fa08559d1fe1a5c37725c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 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 GetLegacyPath(EmuPath::RyujinxDir) / "bis" / "system" / "save" / "8000000000000000" / "0"
           / "imkvdb.arc";
}

fs::path GetRyuSavePath(const u64 &save_id)
{
    std::string hex = fmt::format("{:016x}", save_id);

    // TODO: what's the difference between 0 and 1?
    return GetLegacyPath(EmuPath::RyujinxDir) / "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