From 2164702cf7f878c84a1f148daca2416911e6e939 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Thu, 16 Aug 2018 17:02:31 -0400
Subject: [PATCH] nax: Add AppLoader_NAX and update loader to support it

---
 src/core/loader/loader.cpp | 14 ++++++--
 src/core/loader/loader.h   |  1 +
 src/core/loader/nax.cpp    | 65 ++++++++++++++++++++++++++++++++++++++
 src/core/loader/nax.h      | 43 +++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 src/core/loader/nax.cpp
 create mode 100644 src/core/loader/nax.h

diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 70ef5d240d..fe5d71f68b 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -11,6 +11,7 @@
 #include "core/hle/kernel/process.h"
 #include "core/loader/deconstructed_rom_directory.h"
 #include "core/loader/elf.h"
+#include "core/loader/nax.h"
 #include "core/loader/nca.h"
 #include "core/loader/nro.h"
 #include "core/loader/nso.h"
@@ -32,6 +33,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
     CHECK_TYPE(NRO)
     CHECK_TYPE(NCA)
     CHECK_TYPE(XCI)
+    CHECK_TYPE(NAX)
 
 #undef CHECK_TYPE
 
@@ -73,6 +75,8 @@ std::string GetFileTypeString(FileType type) {
         return "NCA";
     case FileType::XCI:
         return "XCI";
+    case FileType::NAX:
+        return "NAX";
     case FileType::DeconstructedRomDirectory:
         return "Directory";
     case FileType::Error:
@@ -150,13 +154,18 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
     case FileType::NRO:
         return std::make_unique<AppLoader_NRO>(std::move(file));
 
-    // NX NCA file format.
+    // NX NCA (Nintendo Content Archive) file format.
     case FileType::NCA:
         return std::make_unique<AppLoader_NCA>(std::move(file));
 
+    // NX XCI (nX Card Image) file format.
     case FileType::XCI:
         return std::make_unique<AppLoader_XCI>(std::move(file));
 
+    // NX NAX (NintendoAesXts) file format.
+    case FileType::NAX:
+        return std::make_unique<AppLoader_NAX>(std::move(file));
+
     // NX deconstructed ROM directory.
     case FileType::DeconstructedRomDirectory:
         return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file));
@@ -170,7 +179,8 @@ std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) {
     FileType type = IdentifyFile(file);
     FileType filename_type = GuessFromFilename(file->GetName());
 
-    if (type != filename_type) {
+    // Special case: 00 is either a NCA or NAX.
+    if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) {
         LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName());
         if (FileType::Unknown == type)
             type = filename_type;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index b74cfbf8a8..d132fb4e8f 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -32,6 +32,7 @@ enum class FileType {
     NRO,
     NCA,
     XCI,
+    NAX,
     DeconstructedRomDirectory,
 };
 
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
new file mode 100644
index 0000000000..76390bf46f
--- /dev/null
+++ b/src/core/loader/nax.cpp
@@ -0,0 +1,65 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/romfs.h"
+#include "core/hle/kernel/process.h"
+#include "core/loader/nax.h"
+
+namespace Loader {
+
+AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
+    : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
+      nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {}
+
+AppLoader_NAX::~AppLoader_NAX() = default;
+
+FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
+    FileSys::NAX nax(file);
+
+    if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr &&
+        nax.AsNCA()->GetStatus() == ResultStatus::Success) {
+        return FileType::NAX;
+    }
+
+    return FileType::Error;
+}
+
+ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+    if (is_loaded) {
+        return ResultStatus::ErrorAlreadyLoaded;
+    }
+
+    if (nax->GetStatus() != ResultStatus::Success)
+        return nax->GetStatus();
+
+    const auto nca = nax->AsNCA();
+    if (nca == nullptr) {
+        if (!Core::Crypto::KeyManager::KeyFileExists(false))
+            return ResultStatus::ErrorMissingProductionKeyFile;
+        return ResultStatus::ErrorNAXInconvertibleToNCA;
+    }
+
+    if (nca->GetStatus() != ResultStatus::Success)
+        return nca->GetStatus();
+
+    const auto result = nca_loader->Load(process);
+    if (result != ResultStatus::Success)
+        return result;
+
+    is_loaded = true;
+
+    return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) {
+    return nca_loader->ReadRomFS(dir);
+}
+
+ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) {
+    return nca_loader->ReadProgramId(out_program_id);
+}
+} // namespace Loader
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
new file mode 100644
index 0000000000..08d6ef3465
--- /dev/null
+++ b/src/core/loader/nax.h
@@ -0,0 +1,43 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "common/common_types.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/xts_archive.h"
+#include "core/loader/loader.h"
+#include "core/loader/nca.h"
+
+namespace Loader {
+
+/// Loads a NAX file
+class AppLoader_NAX final : public AppLoader {
+public:
+    explicit AppLoader_NAX(FileSys::VirtualFile file);
+    ~AppLoader_NAX();
+
+    /**
+     * Returns the type of the file
+     * @param file std::shared_ptr<VfsFile> open file
+     * @return FileType found, or FileType::Error if this loader doesn't know it
+     */
+    static FileType IdentifyType(const FileSys::VirtualFile& file);
+
+    FileType GetFileType() override {
+        return IdentifyType(file);
+    }
+
+    ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+
+    ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+    ResultStatus ReadProgramId(u64& out_program_id) override;
+
+private:
+    std::unique_ptr<FileSys::NAX> nax;
+    std::unique_ptr<AppLoader_NCA> nca_loader;
+};
+
+} // namespace Loader
-- 
GitLab