فهرست منبع

Merge pull request #11309 from liamwhite/full-xci

file_sys/card_image: support dumps with prepended key area
liamwhite 2 سال پیش
والد
کامیت
9d6ac28999
2فایلهای تغییر یافته به همراه42 افزوده شده و 7 حذف شده
  1. 41 7
      src/core/file_sys/card_image.cpp
  2. 1 0
      src/core/file_sys/card_image.h

+ 41 - 7
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;
 }

+ 1 - 0
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{};