mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-06 08:39:06 +00:00
Remove ResultStatus
And instead use bool to represent result, which is simpler and more consistent, as there's no error reporting anyways.
This commit is contained in:
@@ -31,7 +31,6 @@ add_library(core STATIC
|
|||||||
ncch/title_metadata.h
|
ncch/title_metadata.h
|
||||||
quick_decryptor.cpp
|
quick_decryptor.cpp
|
||||||
quick_decryptor.h
|
quick_decryptor.h
|
||||||
result_status.h
|
|
||||||
savegame.cpp
|
savegame.cpp
|
||||||
savegame.h
|
savegame.h
|
||||||
title_db.cpp
|
title_db.cpp
|
||||||
|
|||||||
+11
-14
@@ -506,10 +506,9 @@ bool SDMCImporter::LoadTMD(ContentType type, u64 id, TitleMetadata& out) const {
|
|||||||
LOG_ERROR(Core, "Could not open {} or file too big", tmd_path);
|
LOG_ERROR(Core, "Could not open {} or file too big", tmd_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return out.Load(file.GetData()) == ResultStatus::Success;
|
return out.Load(file.GetData());
|
||||||
} else {
|
} else {
|
||||||
return out.Load(decryptor->DecryptFile(tmd_path.substr(config.sdmc_path.size() - 1))) ==
|
return out.Load(decryptor->DecryptFile(tmd_path.substr(config.sdmc_path.size() - 1)));
|
||||||
ResultStatus::Success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,7 +529,7 @@ TitleData LoadTitleData(NCCHContainer& ncch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> smdh_buffer;
|
std::vector<u8> smdh_buffer;
|
||||||
if (ncch.LoadSectionExeFS("icon", smdh_buffer) != ResultStatus::Success) {
|
if (!ncch.LoadSectionExeFS("icon", smdh_buffer)) {
|
||||||
LOG_WARNING(Core, "Failed to load icon in ExeFS");
|
LOG_WARNING(Core, "Failed to load icon in ExeFS");
|
||||||
TitleData data{};
|
TitleData data{};
|
||||||
std::get<0>(data) = std::move(title_name_from_codeset);
|
std::get<0>(data) = std::move(title_name_from_codeset);
|
||||||
@@ -590,8 +589,7 @@ static std::string GetTitleFileName(NCCHContainer& ncch) {
|
|||||||
ncch.ReadProgramId(program_id);
|
ncch.ReadProgramId(program_id);
|
||||||
|
|
||||||
std::vector<u8> smdh_buffer;
|
std::vector<u8> smdh_buffer;
|
||||||
if (ncch.LoadSectionExeFS("icon", smdh_buffer) != ResultStatus::Success ||
|
if (!ncch.LoadSectionExeFS("icon", smdh_buffer) || smdh_buffer.size() != sizeof(SMDH)) {
|
||||||
smdh_buffer.size() != sizeof(SMDH)) {
|
|
||||||
LOG_WARNING(Core, "Failed to load icon in ExeFS or size incorrect");
|
LOG_WARNING(Core, "Failed to load icon in ExeFS or size incorrect");
|
||||||
return NormalizeFilename(
|
return NormalizeFilename(
|
||||||
fmt::format("{:016x} {} ({})", program_id, codeset_name, product_code));
|
fmt::format("{:016x} {} ({})", program_id, codeset_name, product_code));
|
||||||
@@ -636,13 +634,12 @@ bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, std::string destin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_cxi_ncch->DecryptToFile(std::make_shared<FileUtil::IOFile>(destination, "wb"),
|
if (!dump_cxi_ncch->DecryptToFile(std::make_shared<FileUtil::IOFile>(destination, "wb"),
|
||||||
callback) == ResultStatus::Success) {
|
callback)) {
|
||||||
return true;
|
FileUtil::Delete(destination);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
FileUtil::Delete(destination);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDMCImporter::AbortDumpCXI() {
|
void SDMCImporter::AbortDumpCXI() {
|
||||||
@@ -828,7 +825,7 @@ void SDMCImporter::ListTitle(std::vector<ContentSpecifier>& out) const {
|
|||||||
virtual_name, tmd.GetBootContentID());
|
virtual_name, tmd.GetBootContentID());
|
||||||
NCCHContainer ncch(
|
NCCHContainer ncch(
|
||||||
std::make_shared<SDMCFile>(sdmc_path, boot_content_path, "rb"));
|
std::make_shared<SDMCFile>(sdmc_path, boot_content_path, "rb"));
|
||||||
if (ncch.Load() != ResultStatus::Success) {
|
if (!ncch.Load()) {
|
||||||
LOG_WARNING(Core, "Could not load NCCH {}", boot_content_path);
|
LOG_WARNING(Core, "Could not load NCCH {}", boot_content_path);
|
||||||
out.push_back({type, id, FileUtil::Exists(citra_path + "content/"),
|
out.push_back({type, id, FileUtil::Exists(citra_path + "content/"),
|
||||||
FileUtil::GetDirectoryTreeSize(directory + virtual_name +
|
FileUtil::GetDirectoryTreeSize(directory + virtual_name +
|
||||||
@@ -907,7 +904,7 @@ void SDMCImporter::ListNandTitle(std::vector<ContentSpecifier>& out) const {
|
|||||||
fmt::format("{}{:08x}.app", content_path, tmd.GetBootContentID());
|
fmt::format("{}{:08x}.app", content_path, tmd.GetBootContentID());
|
||||||
NCCHContainer ncch(
|
NCCHContainer ncch(
|
||||||
std::make_shared<FileUtil::IOFile>(boot_content_path, "rb"));
|
std::make_shared<FileUtil::IOFile>(boot_content_path, "rb"));
|
||||||
if (ncch.Load() != ResultStatus::Success) {
|
if (!ncch.Load()) {
|
||||||
LOG_WARNING(Core, "Could not load NCCH {}", boot_content_path);
|
LOG_WARNING(Core, "Could not load NCCH {}", boot_content_path);
|
||||||
out.push_back({ContentType::SystemTitle, id,
|
out.push_back({ContentType::SystemTitle, id,
|
||||||
FileUtil::Exists(citra_path + "content/"),
|
FileUtil::Exists(citra_path + "content/"),
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) {
|
bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) {
|
||||||
if (ncch.Load() != ResultStatus::Success) {
|
if (!ncch.Load()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) {
|
|||||||
abort_ncch = nullptr;
|
abort_ncch = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != ResultStatus::Success) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
file->GetHash(tmd_chunk.hash.data());
|
file->GetHash(tmd_chunk.hash.data());
|
||||||
@@ -332,7 +332,7 @@ bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) {
|
|||||||
meta.core_version = ncch.exheader_header.arm11_system_local_caps.core_version;
|
meta.core_version = ncch.exheader_header.arm11_system_local_caps.core_version;
|
||||||
|
|
||||||
std::vector<u8> smdh_buffer;
|
std::vector<u8> smdh_buffer;
|
||||||
if (ncch.LoadSectionExeFS("icon", smdh_buffer) != ResultStatus::Success) {
|
if (!ncch.LoadSectionExeFS("icon", smdh_buffer)) {
|
||||||
LOG_WARNING(Core, "Failed to load icon in ExeFS");
|
LOG_WARNING(Core, "Failed to load icon in ExeFS");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -355,7 +355,7 @@ bool CIABuilder::Finalize() {
|
|||||||
tmd.FixHashes();
|
tmd.FixHashes();
|
||||||
}
|
}
|
||||||
file->Seek(tmd_offset, SEEK_SET);
|
file->Seek(tmd_offset, SEEK_SET);
|
||||||
if (tmd.Save(*file) != ResultStatus::Success) {
|
if (!tmd.Save(*file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,34 +27,37 @@ static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes)
|
|||||||
|
|
||||||
NCCHContainer::NCCHContainer(std::shared_ptr<FileUtil::IOFile> file_) : file(std::move(file_)) {}
|
NCCHContainer::NCCHContainer(std::shared_ptr<FileUtil::IOFile> file_) : file(std::move(file_)) {}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::OpenFile(std::shared_ptr<FileUtil::IOFile> file_) {
|
bool NCCHContainer::OpenFile(std::shared_ptr<FileUtil::IOFile> file_) {
|
||||||
file = std::move(file_);
|
file = std::move(file_);
|
||||||
|
|
||||||
if (!file->IsOpen()) {
|
if (!file->IsOpen()) {
|
||||||
LOG_WARNING(Service_FS, "Failed to open");
|
LOG_WARNING(Service_FS, "Failed to open");
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG(Service_FS, "Opened");
|
LOG_DEBUG(Service_FS, "Opened");
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::Load() {
|
bool NCCHContainer::Load() {
|
||||||
if (is_loaded)
|
if (is_loaded)
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
|
|
||||||
if (file->IsOpen()) {
|
if (file->IsOpen()) {
|
||||||
// Reset read pointer in case this file has been read before.
|
// Reset read pointer in case this file has been read before.
|
||||||
file->Seek(0, SEEK_SET);
|
file->Seek(0, SEEK_SET);
|
||||||
|
|
||||||
if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
|
if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) {
|
||||||
return ResultStatus::Error;
|
LOG_ERROR(Service_FS, "Could not read from file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify we are loading the correct file type...
|
// Verify we are loading the correct file type...
|
||||||
if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic)
|
if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic) {
|
||||||
return ResultStatus::ErrorInvalidFormat;
|
LOG_ERROR(Service_FS, "Invalid magic, file may be corrupted");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
has_header = true;
|
|
||||||
bool failed_to_decrypt = false;
|
bool failed_to_decrypt = false;
|
||||||
if (!ncch_header.no_crypto) {
|
if (!ncch_header.no_crypto) {
|
||||||
is_encrypted = true;
|
is_encrypted = true;
|
||||||
@@ -173,13 +176,10 @@ ResultStatus NCCHContainer::Load() {
|
|||||||
|
|
||||||
// System archives and DLC don't have an extended header but have RomFS
|
// System archives and DLC don't have an extended header but have RomFS
|
||||||
if (ncch_header.extended_header_size) {
|
if (ncch_header.extended_header_size) {
|
||||||
auto read_exheader = [this](FileUtil::IOFile& file) {
|
if (file->ReadBytes(&exheader_header,
|
||||||
const std::size_t size = sizeof(exheader_header);
|
sizeof(exheader_header) != sizeof(exheader_header))) {
|
||||||
return file && file.ReadBytes(&exheader_header, size) == size;
|
LOG_ERROR(Service_FS, "Could not read exheader from file");
|
||||||
};
|
return false;
|
||||||
|
|
||||||
if (!read_exheader(*file)) {
|
|
||||||
return ResultStatus::Error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
@@ -193,7 +193,7 @@ ResultStatus NCCHContainer::Load() {
|
|||||||
} else {
|
} else {
|
||||||
if (failed_to_decrypt) {
|
if (failed_to_decrypt) {
|
||||||
LOG_ERROR(Service_FS, "Failed to decrypt");
|
LOG_ERROR(Service_FS, "Failed to decrypt");
|
||||||
return ResultStatus::ErrorEncrypted;
|
return false;
|
||||||
}
|
}
|
||||||
CryptoPP::byte* data = reinterpret_cast<CryptoPP::byte*>(&exheader_header);
|
CryptoPP::byte* data = reinterpret_cast<CryptoPP::byte*>(&exheader_header);
|
||||||
CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption(
|
CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption(
|
||||||
@@ -235,8 +235,10 @@ ResultStatus NCCHContainer::Load() {
|
|||||||
LOG_DEBUG(Service_FS, "ExeFS offset: 0x{:08X}", exefs_offset);
|
LOG_DEBUG(Service_FS, "ExeFS offset: 0x{:08X}", exefs_offset);
|
||||||
LOG_DEBUG(Service_FS, "ExeFS size: 0x{:08X}", exefs_size);
|
LOG_DEBUG(Service_FS, "ExeFS size: 0x{:08X}", exefs_size);
|
||||||
file->Seek(exefs_offset, SEEK_SET);
|
file->Seek(exefs_offset, SEEK_SET);
|
||||||
if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
|
if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) {
|
||||||
return ResultStatus::Error;
|
LOG_ERROR(Service_FS, "Could not read ExeFS header from file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
CryptoPP::byte* data = reinterpret_cast<CryptoPP::byte*>(&exefs_header);
|
CryptoPP::byte* data = reinterpret_cast<CryptoPP::byte*>(&exefs_header);
|
||||||
@@ -254,16 +256,18 @@ ResultStatus NCCHContainer::Load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
|
bool NCCHContainer::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!exefs_file || !exefs_file->IsOpen())
|
if (!exefs_file || !exefs_file->IsOpen()) {
|
||||||
return ResultStatus::Error;
|
LOG_ERROR(Service_FS, "NCCH does not have ExeFS");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG(Service_FS, "{} sections:", kMaxSections);
|
LOG_DEBUG(Service_FS, "{} sections:", kMaxSections);
|
||||||
// Iterate through the ExeFs archive until we find a section with the specified name...
|
// Iterate through the ExeFs archive until we find a section with the specified name...
|
||||||
@@ -283,36 +287,36 @@ ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vector<u8>&
|
|||||||
|
|
||||||
buffer.resize(section.size);
|
buffer.resize(section.size);
|
||||||
if (exefs_file->ReadBytes(&buffer[0], section.size) != section.size)
|
if (exefs_file->ReadBytes(&buffer[0], section.size) != section.size)
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
dec.ProcessData(&buffer[0], &buffer[0], section.size);
|
dec.ProcessData(&buffer[0], &buffer[0], section.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ResultStatus::ErrorNotUsed;
|
LOG_ERROR(Service_FS, "Section {} not found", name);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadProgramId(u64_le& program_id) {
|
bool NCCHContainer::ReadProgramId(u64_le& program_id) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_header)
|
|
||||||
return ResultStatus::ErrorNotUsed;
|
|
||||||
|
|
||||||
program_id = ncch_header.program_id;
|
program_id = ncch_header.program_id;
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadExtdataId(u64& extdata_id) {
|
bool NCCHContainer::ReadExtdataId(u64& extdata_id) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_exheader)
|
if (!has_exheader) {
|
||||||
return ResultStatus::ErrorNotUsed;
|
LOG_ERROR(Service_FS, "NCCH does not have ExHeader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (exheader_header.arm11_system_local_caps.storage_info.other_attributes >> 1) {
|
if (exheader_header.arm11_system_local_caps.storage_info.other_attributes >> 1) {
|
||||||
// Using extended save data access
|
// Using extended save data access
|
||||||
@@ -330,65 +334,65 @@ ResultStatus NCCHContainer::ReadExtdataId(u64& extdata_id) {
|
|||||||
if (id) {
|
if (id) {
|
||||||
// Found a non-zero ID, use it
|
// Found a non-zero ID, use it
|
||||||
extdata_id = id;
|
extdata_id = id;
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultStatus::ErrorNotUsed;
|
LOG_INFO(Service_FS, "Title does not have extdata ID");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
extdata_id = exheader_header.arm11_system_local_caps.storage_info.ext_save_data_id;
|
extdata_id = exheader_header.arm11_system_local_caps.storage_info.ext_save_data_id;
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NCCHContainer::HasExeFS() {
|
bool NCCHContainer::HasExeFS() {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return has_exefs;
|
return has_exefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NCCHContainer::HasExHeader() {
|
bool NCCHContainer::HasExHeader() {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return has_exheader;
|
return has_exheader;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadCodesetName(std::string& name) {
|
bool NCCHContainer::ReadCodesetName(std::string& name) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_exheader)
|
if (!has_exheader) {
|
||||||
return ResultStatus::ErrorNotUsed;
|
LOG_ERROR(Service_FS, "NCCH does not have ExHeader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<char, 9> name_data{};
|
std::array<char, 9> name_data{};
|
||||||
std::memcpy(name_data.data(), exheader_header.codeset_info.name, 8);
|
std::memcpy(name_data.data(), exheader_header.codeset_info.name, 8);
|
||||||
name = name_data.data();
|
name = name_data.data();
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadProductCode(std::string& product_code) {
|
bool NCCHContainer::ReadProductCode(std::string& product_code) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
std::array<char, 17> data{};
|
std::array<char, 17> data{};
|
||||||
std::memcpy(data.data(), ncch_header.product_code, 16);
|
std::memcpy(data.data(), ncch_header.product_code, 16);
|
||||||
product_code = data.data();
|
product_code = data.data();
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadEncryptionType(EncryptionType& encryption) {
|
bool NCCHContainer::ReadEncryptionType(EncryptionType& encryption) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_header)
|
|
||||||
return ResultStatus::ErrorNotUsed;
|
|
||||||
|
|
||||||
if (!is_encrypted) {
|
if (!is_encrypted) {
|
||||||
encryption = EncryptionType::None;
|
encryption = EncryptionType::None;
|
||||||
@@ -410,37 +414,31 @@ ResultStatus NCCHContainer::ReadEncryptionType(EncryptionType& encryption) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Service_FS, "Unknown encryption type {:X}!", ncch_header.secondary_key_slot);
|
LOG_ERROR(Service_FS, "Unknown encryption type {:X}!", ncch_header.secondary_key_slot);
|
||||||
return ResultStatus::ErrorNotUsed;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadSeedCrypto(bool& used) {
|
bool NCCHContainer::ReadSeedCrypto(bool& used) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_header)
|
|
||||||
return ResultStatus::ErrorNotUsed;
|
|
||||||
|
|
||||||
used = ncch_header.seed_crypto;
|
used = ncch_header.seed_crypto;
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest_file,
|
bool NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest_file,
|
||||||
const Common::ProgressCallback& callback) {
|
const Common::ProgressCallback& callback) {
|
||||||
ResultStatus result = Load();
|
if (!Load()) {
|
||||||
if (result != ResultStatus::Success)
|
return false;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
if (!has_header)
|
|
||||||
return ResultStatus::ErrorNotUsed;
|
|
||||||
|
|
||||||
if (!*dest_file) {
|
if (!*dest_file) {
|
||||||
LOG_ERROR(Core, "File is not open");
|
LOG_ERROR(Core, "File is not open");
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_encrypted) {
|
if (!is_encrypted) {
|
||||||
@@ -451,8 +449,7 @@ ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest
|
|||||||
|
|
||||||
decryptor.Reset(size);
|
decryptor.Reset(size);
|
||||||
decryptor.SetCrypto(nullptr);
|
decryptor.SetCrypto(nullptr);
|
||||||
const bool ret = decryptor.CryptAndWriteFile(file, size, dest_file, callback);
|
return decryptor.CryptAndWriteFile(file, size, dest_file, callback);
|
||||||
return ret ? ResultStatus::Success : ResultStatus::Error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto total_size = file->GetSize();
|
const auto total_size = file->GetSize();
|
||||||
@@ -476,7 +473,7 @@ ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest
|
|||||||
if (dest_file->WriteBytes(&modified_header, sizeof(modified_header)) !=
|
if (dest_file->WriteBytes(&modified_header, sizeof(modified_header)) !=
|
||||||
sizeof(modified_header)) {
|
sizeof(modified_header)) {
|
||||||
LOG_ERROR(Core, "Could not write NCCH header to file");
|
LOG_ERROR(Core, "Could not write NCCH header to file");
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
written += sizeof(NCCH_Header);
|
written += sizeof(NCCH_Header);
|
||||||
|
|
||||||
@@ -485,7 +482,7 @@ ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest
|
|||||||
if (dest_file->WriteBytes(&exheader_header, sizeof(exheader_header)) !=
|
if (dest_file->WriteBytes(&exheader_header, sizeof(exheader_header)) !=
|
||||||
sizeof(exheader_header)) {
|
sizeof(exheader_header)) {
|
||||||
LOG_ERROR(Core, "Could not write Exheader to file");
|
LOG_ERROR(Core, "Could not write Exheader to file");
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
written += sizeof(ExHeader_Header);
|
written += sizeof(ExHeader_Header);
|
||||||
}
|
}
|
||||||
@@ -533,19 +530,19 @@ ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest
|
|||||||
|
|
||||||
if (!Write("logo", ncch_header.logo_region_offset * 0x200,
|
if (!Write("logo", ncch_header.logo_region_offset * 0x200,
|
||||||
ncch_header.logo_region_size * 0x200)) {
|
ncch_header.logo_region_size * 0x200)) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Write("plain region", ncch_header.plain_region_offset * 0x200,
|
if (!Write("plain region", ncch_header.plain_region_offset * 0x200,
|
||||||
ncch_header.plain_region_size * 0x200)) {
|
ncch_header.plain_region_size * 0x200)) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write ExeFS header
|
// Write ExeFS header
|
||||||
if (has_exefs) {
|
if (has_exefs) {
|
||||||
if (dest_file->WriteBytes(&exefs_header, sizeof(exefs_header)) != sizeof(exefs_header)) {
|
if (dest_file->WriteBytes(&exefs_header, sizeof(exefs_header)) != sizeof(exefs_header)) {
|
||||||
LOG_ERROR(Core, "Could not write ExeFS header to file");
|
LOG_ERROR(Core, "Could not write ExeFS header to file");
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
written += sizeof(ExeFs_Header);
|
written += sizeof(ExeFs_Header);
|
||||||
|
|
||||||
@@ -565,21 +562,21 @@ ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest
|
|||||||
// Plus 1 for the ExeFS header
|
// Plus 1 for the ExeFS header
|
||||||
if (!Write(section.name, section.offset + (ncch_header.exefs_offset + 1) * 0x200,
|
if (!Write(section.name, section.offset + (ncch_header.exefs_offset + 1) * 0x200,
|
||||||
section.size, true, key, exefs_ctr, section.offset + sizeof(exefs_header))) {
|
section.size, true, key, exefs_ctr, section.offset + sizeof(exefs_header))) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_romfs && !Write("romfs", ncch_header.romfs_offset * 0x200,
|
if (has_romfs && !Write("romfs", ncch_header.romfs_offset * 0x200,
|
||||||
ncch_header.romfs_size * 0x200, true, secondary_key, romfs_ctr)) {
|
ncch_header.romfs_size * 0x200, true, secondary_key, romfs_ctr)) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
if (written < total_size) {
|
if (written < total_size) {
|
||||||
LOG_WARNING(Core, "Data after {} ignored", written);
|
LOG_WARNING(Core, "Data after {} ignored", written);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(total_size, total_size);
|
callback(total_size, total_size);
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NCCHContainer::AbortDecryptToFile() {
|
void NCCHContainer::AbortDecryptToFile() {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/decryptor.h"
|
#include "core/decryptor.h"
|
||||||
#include "core/result_status.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -211,33 +210,29 @@ public:
|
|||||||
NCCHContainer(std::shared_ptr<FileUtil::IOFile> file);
|
NCCHContainer(std::shared_ptr<FileUtil::IOFile> file);
|
||||||
NCCHContainer() {}
|
NCCHContainer() {}
|
||||||
|
|
||||||
ResultStatus OpenFile(std::shared_ptr<FileUtil::IOFile> file);
|
bool OpenFile(std::shared_ptr<FileUtil::IOFile> file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure ExeFS and exheader is loaded and ready for reading sections
|
* Ensure ExeFS and exheader is loaded and ready for reading sections
|
||||||
* @return ResultStatus result of function
|
|
||||||
*/
|
*/
|
||||||
ResultStatus Load();
|
bool Load();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads an application ExeFS section of an NCCH file (non-compressed, primary key only)
|
* Reads an application ExeFS section of an NCCH file (non-compressed, primary key only)
|
||||||
* @param name Name of section to read out of NCCH file
|
* @param name Name of section to read out of NCCH file
|
||||||
* @param buffer Vector to read data into
|
* @param buffer Vector to read data into
|
||||||
* @return ResultStatus result of function
|
|
||||||
*/
|
*/
|
||||||
ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
|
bool LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Program ID of the NCCH container
|
* Get the Program ID of the NCCH container
|
||||||
* @return ResultStatus result of function
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadProgramId(u64_le& program_id);
|
bool ReadProgramId(u64_le& program_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Extdata ID of the NCCH container
|
* Get the Extdata ID of the NCCH container
|
||||||
* @return ResultStatus result of function
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadExtdataId(u64& extdata_id);
|
bool ReadExtdataId(u64& extdata_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the NCCH container contains an ExeFS
|
* Checks whether the NCCH container contains an ExeFS
|
||||||
@@ -253,33 +248,28 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the name of the codeset.
|
* Reads the name of the codeset.
|
||||||
* @return ResultStatus result of function.
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadCodesetName(std::string& name);
|
bool ReadCodesetName(std::string& name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the product code.
|
* Reads the product code.
|
||||||
* @return ResultStatus result of function.
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadProductCode(std::string& name);
|
bool ReadProductCode(std::string& name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets encryption type (which key is used).
|
* Gets encryption type (which key is used).
|
||||||
* @return ResultStatus result of function.
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadEncryptionType(EncryptionType& encryption);
|
bool ReadEncryptionType(EncryptionType& encryption);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether seed crypto is used.
|
* Gets whether seed crypto is used.
|
||||||
* @return ResultStatus result of function.
|
|
||||||
*/
|
*/
|
||||||
ResultStatus ReadSeedCrypto(bool& used);
|
bool ReadSeedCrypto(bool& used);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts this NCCH and write to the destination file.
|
* Decrypts this NCCH and write to the destination file.
|
||||||
* @return ResultStatus result of function.
|
|
||||||
*/
|
*/
|
||||||
ResultStatus DecryptToFile(
|
bool DecryptToFile(
|
||||||
std::shared_ptr<FileUtil::IOFile> dest_file,
|
std::shared_ptr<FileUtil::IOFile> dest_file,
|
||||||
const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
|
const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
|
||||||
|
|
||||||
@@ -293,7 +283,6 @@ public:
|
|||||||
ExeFs_Header exefs_header;
|
ExeFs_Header exefs_header;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool has_header = false;
|
|
||||||
bool has_exheader = false;
|
bool has_exheader = false;
|
||||||
bool has_exefs = false;
|
bool has_exefs = false;
|
||||||
bool has_romfs = false;
|
bool has_romfs = false;
|
||||||
|
|||||||
@@ -17,18 +17,18 @@
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
ResultStatus TitleMetadata::Load(const std::vector<u8> file_data, std::size_t offset) {
|
bool TitleMetadata::Load(const std::vector<u8> file_data, std::size_t offset) {
|
||||||
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
||||||
if (total_size < sizeof(u32_be))
|
if (total_size < sizeof(u32_be))
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
|
|
||||||
if (!signature.Load(file_data, offset)) {
|
if (!signature.Load(file_data, offset)) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
const auto signature_size = signature.GetSize();
|
const auto signature_size = signature.GetSize();
|
||||||
std::size_t body_end = signature_size + sizeof(Body);
|
std::size_t body_end = signature_size + sizeof(Body);
|
||||||
if (total_size < body_end)
|
if (total_size < body_end)
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
|
|
||||||
// Read TMD body, then load the amount of ContentChunks specified
|
// Read TMD body, then load the amount of ContentChunks specified
|
||||||
std::memcpy(&tmd_body, &file_data[offset + signature_size], sizeof(TitleMetadata::Body));
|
std::memcpy(&tmd_body, &file_data[offset + signature_size], sizeof(TitleMetadata::Body));
|
||||||
@@ -38,7 +38,7 @@ ResultStatus TitleMetadata::Load(const std::vector<u8> file_data, std::size_t of
|
|||||||
if (total_size < expected_size) {
|
if (total_size < expected_size) {
|
||||||
LOG_ERROR(Service_FS, "Malformed TMD, expected size 0x{:x}, got 0x{:x}!", expected_size,
|
LOG_ERROR(Service_FS, "Malformed TMD, expected size 0x{:x}, got 0x{:x}!", expected_size,
|
||||||
total_size);
|
total_size);
|
||||||
return ResultStatus::ErrorInvalidFormat;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
||||||
@@ -49,33 +49,33 @@ ResultStatus TitleMetadata::Load(const std::vector<u8> file_data, std::size_t of
|
|||||||
tmd_chunks.push_back(chunk);
|
tmd_chunks.push_back(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus TitleMetadata::Save(FileUtil::IOFile& file) {
|
bool TitleMetadata::Save(FileUtil::IOFile& file) {
|
||||||
const std::size_t offset = file.Tell();
|
const std::size_t offset = file.Tell();
|
||||||
|
|
||||||
if (!file.IsOpen())
|
if (!file.IsOpen())
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
|
|
||||||
if (!signature.Save(file)) {
|
if (!signature.Save(file)) {
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write our TMD body, then write each of our ContentChunks
|
// Write our TMD body, then write each of our ContentChunks
|
||||||
if (file.WriteBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
|
if (file.WriteBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
|
|
||||||
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
||||||
ContentChunk chunk = tmd_chunks[i];
|
ContentChunk chunk = tmd_chunks[i];
|
||||||
if (file.WriteBytes(&chunk, sizeof(ContentChunk)) != sizeof(ContentChunk))
|
if (file.WriteBytes(&chunk, sizeof(ContentChunk)) != sizeof(ContentChunk))
|
||||||
return ResultStatus::Error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus TitleMetadata::Save(const std::string& file_path) {
|
bool TitleMetadata::Save(const std::string& file_path) {
|
||||||
FileUtil::IOFile file(file_path, "wb");
|
FileUtil::IOFile file(file_path, "wb");
|
||||||
return Save(file);
|
return Save(file);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/ncch/signature.h"
|
#include "core/ncch/signature.h"
|
||||||
#include "core/result_status.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -79,9 +78,9 @@ public:
|
|||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
ResultStatus Load(const std::vector<u8> file_data, std::size_t offset = 0);
|
bool Load(const std::vector<u8> file_data, std::size_t offset = 0);
|
||||||
ResultStatus Save(FileUtil::IOFile& file);
|
bool Save(FileUtil::IOFile& file);
|
||||||
ResultStatus Save(const std::string& file_path);
|
bool Save(const std::string& file_path);
|
||||||
|
|
||||||
void FixHashes();
|
void FixHashes();
|
||||||
bool VerifyHashes() const;
|
bool VerifyHashes() const;
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright 2017 Citra Emulator Project / 2019 threeSD Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/// Result code for operations
|
|
||||||
enum class ResultStatus {
|
|
||||||
Success,
|
|
||||||
Error,
|
|
||||||
// Citra loader errors
|
|
||||||
ErrorInvalidFormat,
|
|
||||||
ErrorNotImplemented,
|
|
||||||
ErrorNotLoaded,
|
|
||||||
ErrorNotUsed,
|
|
||||||
ErrorAlreadyLoaded,
|
|
||||||
ErrorMemoryAllocationFailed,
|
|
||||||
ErrorEncrypted,
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user