NRO Assets and NACP file format
Cleanup Review fixes
This commit is contained in:
parent
e85a528bb9
commit
e8f641a52d
5 changed files with 215 additions and 1 deletions
|
@ -12,6 +12,8 @@ add_library(core STATIC
|
||||||
core_timing.h
|
core_timing.h
|
||||||
file_sys/content_archive.cpp
|
file_sys/content_archive.cpp
|
||||||
file_sys/content_archive.h
|
file_sys/content_archive.h
|
||||||
|
file_sys/control_metadata.cpp
|
||||||
|
file_sys/control_metadata.h
|
||||||
file_sys/directory.h
|
file_sys/directory.h
|
||||||
file_sys/errors.h
|
file_sys/errors.h
|
||||||
file_sys/mode.h
|
file_sys/mode.h
|
||||||
|
|
42
src/core/file_sys/control_metadata.cpp
Normal file
42
src/core/file_sys/control_metadata.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "common/swap.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
|
||||||
|
std::string LanguageEntry::GetApplicationName() const {
|
||||||
|
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LanguageEntry::GetDeveloperName() const {
|
||||||
|
return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
NACP::NACP(VirtualFile file_) : file(std::move(file_)), raw(std::make_unique<RawNACP>()) {
|
||||||
|
file->ReadObject(raw.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
|
||||||
|
return raw->language_entries.at(static_cast<u8>(language));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NACP::GetApplicationName(Language language) const {
|
||||||
|
return GetLanguageEntry(language).GetApplicationName();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NACP::GetDeveloperName(Language language) const {
|
||||||
|
return GetLanguageEntry(language).GetDeveloperName();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 NACP::GetTitleId() const {
|
||||||
|
return raw->title_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NACP::GetVersionString() const {
|
||||||
|
return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 0x10);
|
||||||
|
}
|
||||||
|
} // namespace FileSys
|
81
src/core/file_sys/control_metadata.h
Normal file
81
src/core/file_sys/control_metadata.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// 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 <string>
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
|
||||||
|
// A localized entry containing strings within the NACP.
|
||||||
|
// One for each language of type Language.
|
||||||
|
struct LanguageEntry {
|
||||||
|
std::array<char, 0x200> application_name;
|
||||||
|
std::array<char, 0x100> developer_name;
|
||||||
|
|
||||||
|
std::string GetApplicationName() const;
|
||||||
|
std::string GetDeveloperName() const;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size.");
|
||||||
|
|
||||||
|
// The raw file format of a NACP file.
|
||||||
|
struct RawNACP {
|
||||||
|
std::array<LanguageEntry, 16> language_entries;
|
||||||
|
INSERT_PADDING_BYTES(0x38);
|
||||||
|
u64_le title_id;
|
||||||
|
INSERT_PADDING_BYTES(0x20);
|
||||||
|
std::array<char, 0x10> version_string;
|
||||||
|
u64_le dlc_base_title_id;
|
||||||
|
u64_le title_id_2;
|
||||||
|
INSERT_PADDING_BYTES(0x28);
|
||||||
|
u64_le product_code;
|
||||||
|
u64_le title_id_3;
|
||||||
|
std::array<u64_le, 0x7> title_id_array;
|
||||||
|
INSERT_PADDING_BYTES(0x8);
|
||||||
|
u64_le title_id_update;
|
||||||
|
std::array<u8, 0x40> bcat_passphrase;
|
||||||
|
INSERT_PADDING_BYTES(0xEC0);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");
|
||||||
|
|
||||||
|
// A language on the NX. These are for names and icons.
|
||||||
|
enum class Language : u8 {
|
||||||
|
AmericanEnglish = 0,
|
||||||
|
BritishEnglish = 1,
|
||||||
|
Japanese = 2,
|
||||||
|
French = 3,
|
||||||
|
German = 4,
|
||||||
|
LatinAmericanSpanish = 5,
|
||||||
|
Spanish = 6,
|
||||||
|
Italian = 7,
|
||||||
|
Dutch = 8,
|
||||||
|
CanadianFrench = 9,
|
||||||
|
Portugese = 10,
|
||||||
|
Russian = 11,
|
||||||
|
Korean = 12,
|
||||||
|
Taiwanese = 13,
|
||||||
|
Chinese = 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
// A class representing the format used by NX metadata files, typically named Control.nacp.
|
||||||
|
// These store application name, dev name, title id, and other miscellaneous data.
|
||||||
|
class NACP {
|
||||||
|
public:
|
||||||
|
explicit NACP(VirtualFile file);
|
||||||
|
const LanguageEntry& GetLanguageEntry(Language language = Language::AmericanEnglish) const;
|
||||||
|
std::string GetApplicationName(Language language = Language::AmericanEnglish) const;
|
||||||
|
std::string GetDeveloperName(Language language = Language::AmericanEnglish) const;
|
||||||
|
u64 GetTitleId() const;
|
||||||
|
std::string GetVersionString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VirtualFile file;
|
||||||
|
std::unique_ptr<RawNACP> raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace FileSys
|
|
@ -10,6 +10,8 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
#include "core/file_sys/vfs_offset.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
@ -49,7 +51,55 @@ struct ModHeader {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
|
static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
|
||||||
|
|
||||||
AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
|
struct AssetSection {
|
||||||
|
u64_le offset;
|
||||||
|
u64_le size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AssetSection) == 0x10, "AssetSection has incorrect size.");
|
||||||
|
|
||||||
|
struct AssetHeader {
|
||||||
|
u32_le magic;
|
||||||
|
u32_le format_version;
|
||||||
|
AssetSection icon;
|
||||||
|
AssetSection nacp;
|
||||||
|
AssetSection romfs;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size.");
|
||||||
|
|
||||||
|
AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) {
|
||||||
|
NroHeader nro_header{};
|
||||||
|
if (file->ReadObject(&nro_header) != sizeof(NroHeader))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (file->GetSize() >= nro_header.file_size + sizeof(AssetHeader)) {
|
||||||
|
u64 offset = nro_header.file_size;
|
||||||
|
AssetHeader asset_header{};
|
||||||
|
if (file->ReadObject(&asset_header, offset) != sizeof(AssetHeader))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (asset_header.format_version != 0)
|
||||||
|
LOG_WARNING(Loader,
|
||||||
|
"NRO Asset Header has format {}, currently supported format is 0. If "
|
||||||
|
"strange glitches occur with metadata, check NRO assets.",
|
||||||
|
asset_header.format_version);
|
||||||
|
if (asset_header.magic != Common::MakeMagic('A', 'S', 'E', 'T'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (asset_header.nacp.size > 0) {
|
||||||
|
nacp = std::make_unique<FileSys::NACP>(std::make_shared<FileSys::OffsetVfsFile>(
|
||||||
|
file, asset_header.nacp.size, offset + asset_header.nacp.offset, "Control.nacp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset_header.romfs.size > 0) {
|
||||||
|
romfs = std::make_shared<FileSys::OffsetVfsFile>(
|
||||||
|
file, asset_header.romfs.size, offset + asset_header.romfs.offset, "game.romfs");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset_header.icon.size > 0) {
|
||||||
|
icon_data = file->ReadBytes(asset_header.icon.size, offset + asset_header.icon.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
|
FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
|
||||||
// Read NSO header
|
// Read NSO header
|
||||||
|
@ -136,4 +186,31 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
|
||||||
|
if (icon_data.empty())
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
buffer = icon_data;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
|
||||||
|
if (nacp == nullptr)
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
out_program_id = nacp->GetTitleId();
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
|
||||||
|
if (romfs == nullptr)
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
dir = romfs;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
|
||||||
|
if (nacp == nullptr)
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
title = nacp->GetApplicationName();
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/loader/linker.h"
|
#include "core/loader/linker.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Loader {
|
namespace Loader {
|
||||||
|
|
||||||
|
struct AssetHeader;
|
||||||
|
|
||||||
/// Loads an NRO file
|
/// Loads an NRO file
|
||||||
class AppLoader_NRO final : public AppLoader, Linker {
|
class AppLoader_NRO final : public AppLoader, Linker {
|
||||||
public:
|
public:
|
||||||
|
@ -30,8 +33,17 @@ public:
|
||||||
|
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
|
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||||
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
||||||
|
ResultStatus ReadTitle(std::string& title) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool LoadNro(FileSys::VirtualFile file, VAddr load_base);
|
bool LoadNro(FileSys::VirtualFile file, VAddr load_base);
|
||||||
|
|
||||||
|
std::vector<u8> icon_data;
|
||||||
|
std::unique_ptr<FileSys::NACP> nacp;
|
||||||
|
FileSys::VirtualFile romfs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
Loading…
Reference in a new issue