summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-07-23 23:14:11 +0200
committerGitHub <noreply@github.com>2018-07-23 23:14:11 +0200
commit07e5319d552ed1ad9b9fbe47852c581d48c1e46c (patch)
treeb40b503cde453eb513228f67c826f11ff6ef5d1c
parentMerge pull request #778 from lioncash/log (diff)
parentNRO Assets and NACP file format (diff)
downloadyuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar.gz
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar.bz2
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar.lz
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar.xz
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.tar.zst
yuzu-07e5319d552ed1ad9b9fbe47852c581d48c1e46c.zip
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/file_sys/control_metadata.cpp42
-rw-r--r--src/core/file_sys/control_metadata.h81
-rw-r--r--src/core/loader/nro.cpp79
-rw-r--r--src/core/loader/nro.h12
5 files changed, 215 insertions, 1 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 27a5de7fd..fd75854b0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,8 @@ add_library(core STATIC
core_timing.h
file_sys/content_archive.cpp
file_sys/content_archive.h
+ file_sys/control_metadata.cpp
+ file_sys/control_metadata.h
file_sys/directory.h
file_sys/errors.h
file_sys/mode.h
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
new file mode 100644
index 000000000..3ddc9f162
--- /dev/null
+++ b/src/core/file_sys/control_metadata.cpp
@@ -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
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
new file mode 100644
index 000000000..cc3b745f7
--- /dev/null
+++ b/src/core/file_sys/control_metadata.h
@@ -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
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c020399f2..44158655c 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -10,6 +10,8 @@
#include "common/logging/log.h"
#include "common/swap.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/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@@ -49,7 +51,55 @@ struct ModHeader {
};
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) {
// Read NSO header
@@ -136,4 +186,31 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
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
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 2c03d06bb..5f3fc40d2 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -6,12 +6,15 @@
#include <string>
#include "common/common_types.h"
+#include "core/file_sys/control_metadata.h"
#include "core/hle/kernel/kernel.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
namespace Loader {
+struct AssetHeader;
+
/// Loads an NRO file
class AppLoader_NRO final : public AppLoader, Linker {
public:
@@ -30,8 +33,17 @@ public:
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:
bool LoadNro(FileSys::VirtualFile file, VAddr load_base);
+
+ std::vector<u8> icon_data;
+ std::unique_ptr<FileSys::NACP> nacp;
+ FileSys::VirtualFile romfs;
};
} // namespace Loader