|
@@ -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},
|
|
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
|
|
|
partitions(partition_names.size()),
|
|
partitions(partition_names.size()),
|
|
|
partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
|
|
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;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -316,6 +312,44 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
|
|
|
return Loader::ResultStatus::Success;
|
|
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() {
|
|
u8 XCI::GetFormatVersion() {
|
|
|
return GetLogoPartition() == nullptr ? 0x1 : 0x2;
|
|
return GetLogoPartition() == nullptr ? 0x1 : 0x2;
|
|
|
}
|
|
}
|