2018-08-09 20:51:52 -04:00
|
|
|
// Copyright 2018 yuzu emulator team
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2019-06-10 23:48:12 -04:00
|
|
|
#include <array>
|
2018-08-09 20:51:52 -04:00
|
|
|
#include <memory>
|
2018-08-09 23:10:32 -04:00
|
|
|
#include <vector>
|
2018-08-20 20:24:13 -04:00
|
|
|
#include "common/common_funcs.h"
|
2018-08-09 23:10:32 -04:00
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/swap.h"
|
2018-08-09 20:51:52 -04:00
|
|
|
#include "core/file_sys/vfs.h"
|
|
|
|
|
|
|
|
namespace FileSys {
|
|
|
|
class CNMT;
|
|
|
|
|
|
|
|
struct CNMTHeader;
|
|
|
|
struct OptionalHeader;
|
|
|
|
|
|
|
|
enum class TitleType : u8 {
|
|
|
|
SystemProgram = 0x01,
|
|
|
|
SystemDataArchive = 0x02,
|
|
|
|
SystemUpdate = 0x03,
|
|
|
|
FirmwarePackageA = 0x04,
|
|
|
|
FirmwarePackageB = 0x05,
|
|
|
|
Application = 0x80,
|
|
|
|
Update = 0x81,
|
|
|
|
AOC = 0x82,
|
|
|
|
DeltaTitle = 0x83,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class ContentRecordType : u8 {
|
|
|
|
Meta = 0,
|
|
|
|
Program = 1,
|
|
|
|
Data = 2,
|
|
|
|
Control = 3,
|
|
|
|
Manual = 4,
|
|
|
|
Legal = 5,
|
|
|
|
Patch = 6,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ContentRecord {
|
|
|
|
std::array<u8, 0x20> hash;
|
|
|
|
std::array<u8, 0x10> nca_id;
|
|
|
|
std::array<u8, 0x6> size;
|
|
|
|
ContentRecordType type;
|
|
|
|
INSERT_PADDING_BYTES(1);
|
|
|
|
};
|
|
|
|
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
|
|
|
|
|
|
|
|
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, {}};
|
|
|
|
|
|
|
|
struct MetaRecord {
|
|
|
|
u64_le title_id;
|
|
|
|
u32_le title_version;
|
|
|
|
TitleType type;
|
|
|
|
u8 install_byte;
|
|
|
|
INSERT_PADDING_BYTES(2);
|
|
|
|
};
|
|
|
|
static_assert(sizeof(MetaRecord) == 0x10, "MetaRecord has incorrect size.");
|
|
|
|
|
|
|
|
struct OptionalHeader {
|
|
|
|
u64_le title_id;
|
|
|
|
u64_le minimum_version;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(OptionalHeader) == 0x10, "OptionalHeader has incorrect size.");
|
|
|
|
|
|
|
|
struct CNMTHeader {
|
|
|
|
u64_le title_id;
|
|
|
|
u32_le title_version;
|
|
|
|
TitleType type;
|
2019-06-10 23:48:12 -04:00
|
|
|
u8 reserved;
|
2018-08-09 20:51:52 -04:00
|
|
|
u16_le table_offset;
|
|
|
|
u16_le number_content_entries;
|
|
|
|
u16_le number_meta_entries;
|
2019-06-10 23:48:12 -04:00
|
|
|
u8 attributes;
|
|
|
|
std::array<u8, 2> reserved2;
|
|
|
|
u8 is_committed;
|
|
|
|
u32_le required_download_system_version;
|
|
|
|
std::array<u8, 4> reserved3;
|
2018-08-09 20:51:52 -04:00
|
|
|
};
|
|
|
|
static_assert(sizeof(CNMTHeader) == 0x20, "CNMTHeader has incorrect size.");
|
|
|
|
|
|
|
|
// A class representing the format used by NCA metadata files, typically named {}.cnmt.nca or
|
|
|
|
// meta0.ncd. These describe which NCA's belong with which titles in the registered cache.
|
|
|
|
class CNMT {
|
|
|
|
public:
|
|
|
|
explicit CNMT(VirtualFile file);
|
|
|
|
CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
|
|
|
|
std::vector<MetaRecord> meta_records);
|
2018-09-19 19:19:05 -04:00
|
|
|
~CNMT();
|
2018-08-09 20:51:52 -04:00
|
|
|
|
|
|
|
u64 GetTitleID() const;
|
|
|
|
u32 GetTitleVersion() const;
|
|
|
|
TitleType GetType() const;
|
|
|
|
|
|
|
|
const std::vector<ContentRecord>& GetContentRecords() const;
|
|
|
|
const std::vector<MetaRecord>& GetMetaRecords() const;
|
|
|
|
|
|
|
|
bool UnionRecords(const CNMT& other);
|
|
|
|
std::vector<u8> Serialize() const;
|
|
|
|
|
|
|
|
private:
|
2018-08-11 15:39:09 -04:00
|
|
|
CNMTHeader header;
|
|
|
|
OptionalHeader opt_header;
|
2018-08-09 20:51:52 -04:00
|
|
|
std::vector<ContentRecord> content_records;
|
|
|
|
std::vector<MetaRecord> meta_records;
|
|
|
|
|
|
|
|
// TODO(DarkLordZach): According to switchbrew, for Patch-type there is additional data
|
|
|
|
// after the table. This is not documented, unfortunately.
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace FileSys
|