summaryrefslogtreecommitdiffstats
path: root/src/core/file_sys/nca_patch.h
blob: 381f3504fb8ec395d291acda44856878ea6aa268 (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <memory>
#include <vector>

#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"

namespace FileSys {

#pragma pack(push, 1)
struct RelocationEntry {
    u64_le address_patch;
    u64_le address_source;
    u32 from_patch;
};
#pragma pack(pop)
static_assert(sizeof(RelocationEntry) == 0x14, "RelocationEntry has incorrect size.");

struct RelocationBucketRaw {
    INSERT_PADDING_BYTES(4);
    u32_le number_entries;
    u64_le end_offset;
    std::array<RelocationEntry, 0x332> relocation_entries;
    INSERT_PADDING_BYTES(8);
};
static_assert(sizeof(RelocationBucketRaw) == 0x4000, "RelocationBucketRaw has incorrect size.");

// Vector version of RelocationBucketRaw
struct RelocationBucket {
    u32 number_entries;
    u64 end_offset;
    std::vector<RelocationEntry> entries;
};

struct RelocationBlock {
    INSERT_PADDING_BYTES(4);
    u32_le number_buckets;
    u64_le size;
    std::array<u64, 0x7FE> base_offsets;
};
static_assert(sizeof(RelocationBlock) == 0x4000, "RelocationBlock has incorrect size.");

struct SubsectionEntry {
    u64_le address_patch;
    INSERT_PADDING_BYTES(0x4);
    u32_le ctr;
};
static_assert(sizeof(SubsectionEntry) == 0x10, "SubsectionEntry has incorrect size.");

struct SubsectionBucketRaw {
    INSERT_PADDING_BYTES(4);
    u32_le number_entries;
    u64_le end_offset;
    std::array<SubsectionEntry, 0x3FF> subsection_entries;
};
static_assert(sizeof(SubsectionBucketRaw) == 0x4000, "SubsectionBucketRaw has incorrect size.");

// Vector version of SubsectionBucketRaw
struct SubsectionBucket {
    u32 number_entries;
    u64 end_offset;
    std::vector<SubsectionEntry> entries;
};

struct SubsectionBlock {
    INSERT_PADDING_BYTES(4);
    u32_le number_buckets;
    u64_le size;
    std::array<u64, 0x7FE> base_offsets;
};
static_assert(sizeof(SubsectionBlock) == 0x4000, "SubsectionBlock has incorrect size.");

inline RelocationBucket ConvertRelocationBucketRaw(RelocationBucketRaw raw) {
    return {raw.number_entries,
            raw.end_offset,
            {raw.relocation_entries.begin(), raw.relocation_entries.begin() + raw.number_entries}};
}

inline SubsectionBucket ConvertSubsectionBucketRaw(SubsectionBucketRaw raw) {
    return {raw.number_entries,
            raw.end_offset,
            {raw.subsection_entries.begin(), raw.subsection_entries.begin() + raw.number_entries}};
}

class BKTR : public VfsFile {
public:
    BKTR(VirtualFile base_romfs, VirtualFile bktr_romfs, RelocationBlock relocation,
         std::vector<RelocationBucket> relocation_buckets, SubsectionBlock subsection,
         std::vector<SubsectionBucket> subsection_buckets, bool is_encrypted,
         Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr);
    ~BKTR() override;

    size_t Read(u8* data, size_t length, size_t offset) const override;

    std::string GetName() const override;

    size_t GetSize() const override;

    bool Resize(size_t new_size) override;

    std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;

    bool IsWritable() const override;

    bool IsReadable() const override;

    size_t Write(const u8* data, size_t length, size_t offset) override;

    bool Rename(std::string_view name) override;

private:
    template <bool Subsection, typename BlockType, typename BucketType>
    std::pair<size_t, size_t> SearchBucketEntry(u64 offset, BlockType block,
                                                BucketType buckets) const;

    RelocationEntry GetRelocationEntry(u64 offset) const;
    RelocationEntry GetNextRelocationEntry(u64 offset) const;

    SubsectionEntry GetSubsectionEntry(u64 offset) const;
    SubsectionEntry GetNextSubsectionEntry(u64 offset) const;

    RelocationBlock relocation;
    std::vector<RelocationBucket> relocation_buckets;
    SubsectionBlock subsection;
    std::vector<SubsectionBucket> subsection_buckets;

    // Should be the raw base romfs, decrypted.
    VirtualFile base_romfs;
    // Should be the raw BKTR romfs, (located at media_offset with size media_size).
    VirtualFile bktr_romfs;

    bool encrypted;
    Core::Crypto::Key128 key;

    // Base offset into NCA, used for IV calculation.
    u64 base_offset;
    // Distance between IVFC start and RomFS start, used for base reads
    u64 ivfc_offset;
    std::array<u8, 8> section_ctr;
};

} // namespace FileSys