mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	NRO Assets and NACP file format
Cleanup Review fixes
This commit is contained in:
		
							parent
							
								
									e85a528bb9
								
							
						
					
					
						commit
						e8f641a52d
					
				@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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/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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user