From 04868ab9da2049429808a265dc50696f6300b2b4 Mon Sep 17 00:00:00 2001
From: Tobias <thm.frey@gmail.com>
Date: Wed, 12 Jul 2023 23:17:18 +0200
Subject: [PATCH] file_sys/content_archive: Detect compressed NCAs (#11047)

---
 src/core/file_sys/content_archive.cpp | 39 ++++++++++++++++++++++++++-
 src/core/loader/loader.h              |  2 ++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 50303fe42c..06efab46d7 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -57,11 +57,34 @@ struct NCASectionHeaderBlock {
 };
 static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
 
+struct NCABucketInfo {
+    u64 table_offset;
+    u64 table_size;
+    std::array<u8, 0x10> table_header;
+};
+static_assert(sizeof(NCABucketInfo) == 0x20, "NCABucketInfo has incorrect size.");
+
+struct NCASparseInfo {
+    NCABucketInfo bucket;
+    u64 physical_offset;
+    u16 generation;
+    INSERT_PADDING_BYTES_NOINIT(0x6);
+};
+static_assert(sizeof(NCASparseInfo) == 0x30, "NCASparseInfo has incorrect size.");
+
+struct NCACompressionInfo {
+    NCABucketInfo bucket;
+    INSERT_PADDING_BYTES_NOINIT(0x8);
+};
+static_assert(sizeof(NCACompressionInfo) == 0x28, "NCACompressionInfo has incorrect size.");
+
 struct NCASectionRaw {
     NCASectionHeaderBlock header;
     std::array<u8, 0x138> block_data;
     std::array<u8, 0x8> section_ctr;
-    INSERT_PADDING_BYTES_NOINIT(0xB8);
+    NCASparseInfo sparse_info;
+    NCACompressionInfo compression_info;
+    INSERT_PADDING_BYTES_NOINIT(0x60);
 };
 static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
 
@@ -225,6 +248,20 @@ bool NCA::ReadSections(const std::vector<NCASectionHeader>& sections, u64 bktr_b
     for (std::size_t i = 0; i < sections.size(); ++i) {
         const auto& section = sections[i];
 
+        if (section.raw.sparse_info.bucket.table_offset != 0 &&
+            section.raw.sparse_info.bucket.table_size != 0) {
+            LOG_ERROR(Loader, "Sparse NCAs are not supported.");
+            status = Loader::ResultStatus::ErrorSparseNCA;
+            return false;
+        }
+
+        if (section.raw.compression_info.bucket.table_offset != 0 &&
+            section.raw.compression_info.bucket.table_size != 0) {
+            LOG_ERROR(Loader, "Compressed NCAs are not supported.");
+            status = Loader::ResultStatus::ErrorCompressedNCA;
+            return false;
+        }
+
         if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
             if (!ReadRomFSSection(section, header.section_tables[i], bktr_base_ivfc_offset)) {
                 return false;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 7b43f70ed9..7a2a52fd40 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -79,6 +79,8 @@ enum class ResultStatus : u16 {
     ErrorBadPFSHeader,
     ErrorIncorrectPFSFileSize,
     ErrorBadNCAHeader,
+    ErrorCompressedNCA,
+    ErrorSparseNCA,
     ErrorMissingProductionKeyFile,
     ErrorMissingHeaderKey,
     ErrorIncorrectHeaderKey,