mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 18:53:32 +00:00
fix: add missing NCA encryption type support and patch handling
Changes: - Add missing encryption type cases to all switch statements - Only call CreatePatchMetaStorage() when both tables are present - Update assertions to allow partial table combinations Fixes loading for Hades II, Pokémon Legends: Z-A, and other games with newer NCA structures. Reported-by: Dr.Stug@citron-emu.org Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -140,7 +140,7 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
|||||||
const auto& patch_info = out_header_reader->GetPatchInfo();
|
const auto& patch_info = out_header_reader->GetPatchInfo();
|
||||||
VirtualFile patch_meta_aes_ctr_ex_meta_storage;
|
VirtualFile patch_meta_aes_ctr_ex_meta_storage;
|
||||||
VirtualFile patch_meta_indirect_meta_storage;
|
VirtualFile patch_meta_indirect_meta_storage;
|
||||||
if (out_header_reader->ExistsPatchMetaHashLayer()) {
|
if (out_header_reader->ExistsPatchMetaHashLayer() && patch_info.HasAesCtrExTable()) {
|
||||||
// Check the meta hash type.
|
// Check the meta hash type.
|
||||||
R_UNLESS(out_header_reader->GetPatchMetaHashType() ==
|
R_UNLESS(out_header_reader->GetPatchMetaHashType() ==
|
||||||
NcaFsHeader::MetaDataHashType::HierarchicalIntegrity,
|
NcaFsHeader::MetaDataHashType::HierarchicalIntegrity,
|
||||||
@@ -165,8 +165,8 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
|||||||
// Create the ex meta storage.
|
// Create the ex meta storage.
|
||||||
VirtualFile aes_ctr_ex_storage_meta_storage = patch_meta_aes_ctr_ex_meta_storage;
|
VirtualFile aes_ctr_ex_storage_meta_storage = patch_meta_aes_ctr_ex_meta_storage;
|
||||||
if (aes_ctr_ex_storage_meta_storage == nullptr) {
|
if (aes_ctr_ex_storage_meta_storage == nullptr) {
|
||||||
// If we don't have a meta storage, we must not have a patch meta hash layer.
|
// If we don't have a meta storage, we must not have a patch meta hash layer with both tables.
|
||||||
ASSERT(!out_header_reader->ExistsPatchMetaHashLayer());
|
ASSERT(!out_header_reader->ExistsPatchMetaHashLayer() || !patch_info.HasIndirectTable());
|
||||||
|
|
||||||
R_TRY(this->CreateAesCtrExStorageMetaStorage(
|
R_TRY(this->CreateAesCtrExStorageMetaStorage(
|
||||||
std::addressof(aes_ctr_ex_storage_meta_storage), storage, fs_data_offset,
|
std::addressof(aes_ctr_ex_storage_meta_storage), storage, fs_data_offset,
|
||||||
@@ -202,11 +202,13 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
|||||||
fs_data_offset));
|
fs_data_offset));
|
||||||
break;
|
break;
|
||||||
case NcaFsHeader::EncryptionType::AesCtr:
|
case NcaFsHeader::EncryptionType::AesCtr:
|
||||||
|
case NcaFsHeader::EncryptionType::AesCtrEx:
|
||||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
|
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
|
||||||
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
||||||
AlignmentStorageRequirement::None));
|
AlignmentStorageRequirement::None));
|
||||||
break;
|
break;
|
||||||
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: {
|
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash:
|
||||||
|
case NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash: {
|
||||||
// Create the aes ctr storage.
|
// Create the aes ctr storage.
|
||||||
VirtualFile aes_ctr_storage;
|
VirtualFile aes_ctr_storage;
|
||||||
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage,
|
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage,
|
||||||
@@ -232,8 +234,8 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
|||||||
// Create the indirect meta storage.
|
// Create the indirect meta storage.
|
||||||
VirtualFile indirect_storage_meta_storage = patch_meta_indirect_meta_storage;
|
VirtualFile indirect_storage_meta_storage = patch_meta_indirect_meta_storage;
|
||||||
if (indirect_storage_meta_storage == nullptr) {
|
if (indirect_storage_meta_storage == nullptr) {
|
||||||
// If we don't have a meta storage, we must not have a patch meta hash layer.
|
// If we don't have a meta storage, we must not have a patch meta hash layer with AesCtrEx.
|
||||||
ASSERT(!out_header_reader->ExistsPatchMetaHashLayer());
|
ASSERT(!out_header_reader->ExistsPatchMetaHashLayer() || !patch_info.HasAesCtrExTable());
|
||||||
|
|
||||||
R_TRY(this->CreateIndirectStorageMetaStorage(
|
R_TRY(this->CreateIndirectStorageMetaStorage(
|
||||||
std::addressof(indirect_storage_meta_storage), storage, patch_info));
|
std::addressof(indirect_storage_meta_storage), storage, patch_info));
|
||||||
@@ -382,10 +384,33 @@ Result NcaFileSystemDriver::OpenIndirectableStorageAsOriginal(
|
|||||||
this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), fs_data_offset));
|
this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), fs_data_offset));
|
||||||
break;
|
break;
|
||||||
case NcaFsHeader::EncryptionType::AesCtr:
|
case NcaFsHeader::EncryptionType::AesCtr:
|
||||||
|
case NcaFsHeader::EncryptionType::AesCtrEx:
|
||||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), fs_data_offset,
|
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), fs_data_offset,
|
||||||
header_reader->GetAesCtrUpperIv(),
|
header_reader->GetAesCtrUpperIv(),
|
||||||
AlignmentStorageRequirement::CacheBlockSize));
|
AlignmentStorageRequirement::CacheBlockSize));
|
||||||
break;
|
break;
|
||||||
|
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: {
|
||||||
|
// Create the aes ctr storage.
|
||||||
|
VirtualFile aes_ctr_storage;
|
||||||
|
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage, fs_data_offset,
|
||||||
|
header_reader->GetAesCtrUpperIv(),
|
||||||
|
AlignmentStorageRequirement::CacheBlockSize));
|
||||||
|
|
||||||
|
// Create region switch storage.
|
||||||
|
R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), header_reader,
|
||||||
|
std::move(storage), std::move(aes_ctr_storage)));
|
||||||
|
} break;
|
||||||
|
case NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash: {
|
||||||
|
// Create the aes ctr ex storage.
|
||||||
|
VirtualFile aes_ctr_ex_storage;
|
||||||
|
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_ex_storage), storage, fs_data_offset,
|
||||||
|
header_reader->GetAesCtrUpperIv(),
|
||||||
|
AlignmentStorageRequirement::CacheBlockSize));
|
||||||
|
|
||||||
|
// Create region switch storage.
|
||||||
|
R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), header_reader,
|
||||||
|
std::move(storage), std::move(aes_ctr_ex_storage)));
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user