diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/card_image.cpp | 48 | ||||
-rw-r--r-- | src/core/file_sys/card_image.h | 1 |
2 files changed, 42 insertions, 7 deletions
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 5d02865f4..3e667e74a 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -31,13 +31,9 @@ XCI::XCI(VirtualFile file_, u64 program_id, size_t program_index) : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, partitions(partition_names.size()), partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { - if (file->ReadObject(&header) != sizeof(GamecardHeader)) { - status = Loader::ResultStatus::ErrorBadXCIHeader; - return; - } - - if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) { - status = Loader::ResultStatus::ErrorBadXCIHeader; + const auto header_status = TryReadHeader(); + if (header_status != Loader::ResultStatus::Success) { + status = header_status; return; } @@ -316,6 +312,44 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { return Loader::ResultStatus::Success; } +Loader::ResultStatus XCI::TryReadHeader() { + constexpr size_t CardInitialDataRegionSize = 0x1000; + + // Define the function we'll use to determine if we read a valid header. + const auto ReadCardHeader = [&]() { + // Ensure we can read the entire header. If we can't, we can't read the card image. + if (file->ReadObject(&header) != sizeof(GamecardHeader)) { + return Loader::ResultStatus::ErrorBadXCIHeader; + } + + // Ensure the header magic matches. If it doesn't, this isn't a card image header. + if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) { + return Loader::ResultStatus::ErrorBadXCIHeader; + } + + // We read a card image header. + return Loader::ResultStatus::Success; + }; + + // Try to read the header directly. + if (ReadCardHeader() == Loader::ResultStatus::Success) { + return Loader::ResultStatus::Success; + } + + // Get the size of the file. + const size_t card_image_size = file->GetSize(); + + // If we are large enough to have a key area, offset past the key area and retry. + if (card_image_size >= CardInitialDataRegionSize) { + file = std::make_shared<OffsetVfsFile>(file, card_image_size - CardInitialDataRegionSize, + CardInitialDataRegionSize); + return ReadCardHeader(); + } + + // We had no header and aren't large enough to have a key area, so this can't be parsed. + return Loader::ResultStatus::ErrorBadXCIHeader; +} + u8 XCI::GetFormatVersion() { return GetLogoPartition() == nullptr ? 0x1 : 0x2; } diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 1283f8216..9886123e7 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -128,6 +128,7 @@ public: private: Loader::ResultStatus AddNCAFromPartition(XCIPartition part); + Loader::ResultStatus TryReadHeader(); VirtualFile file; GamecardHeader header{}; |