Explorar o código

ns: Implement command 400: GetApplicationControlData

Returns the raw NACP bytes and the raw icon bytes into a title-provided buffer. Pulls from Registration Cache for control data, returning all zeros should it not exist.
Zach Hilman %!s(int64=7) %!d(string=hai) anos
pai
achega
bdaa76c0db

+ 1 - 1
src/core/file_sys/savedata_factory.cpp

@@ -83,7 +83,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
     return MakeResult<VirtualDir>(std::move(out));
 }
 
-VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) {
+VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
     return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
 }
 

+ 1 - 1
src/core/file_sys/savedata_factory.h

@@ -52,7 +52,7 @@ public:
 
     ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
 
-    VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space);
+    VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
 
     static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
     static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,

+ 10 - 14
src/core/hle/service/filesystem/fsp_srv.cpp

@@ -481,9 +481,9 @@ public:
         // Write the data to memory
         ctx.WriteBuffer(begin, range_size);
 
-        IPC::ResponseBuilder rb{ctx, 4};
+        IPC::ResponseBuilder rb{ctx, 3};
         rb.Push(RESULT_SUCCESS);
-        rb.Push(actual_entries);
+        rb.Push<u32>(static_cast<u32>(actual_entries));
     }
 
 private:
@@ -498,15 +498,6 @@ private:
         return Common::swap64(out);
     }
 
-    static std::array<u8, 0x10> ArraySwap(const std::array<u8, 0x10>& in) {
-        std::array<u8, 0x10> out;
-        for (std::size_t i = 0; i < in.size(); ++i) {
-            out[0xF - i] = in[i];
-        }
-
-        return out;
-    }
-
     void FindAllSaves(FileSys::SaveDataSpaceId space) {
         const auto save_root = OpenSaveDataSpace(space);
         ASSERT(save_root.Succeeded());
@@ -516,8 +507,9 @@ private:
                 for (const auto& save_id : type->GetSubdirectories()) {
                     for (const auto& user_id : save_id->GetSubdirectories()) {
                         const auto save_id_numeric = stoull_be(save_id->GetName());
-                        const auto user_id_numeric =
-                            ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName()));
+                        auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+                        std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
                         if (save_id_numeric != 0) {
                             // System Save Data
                             info.emplace_back(SaveDataInfo{
@@ -560,12 +552,16 @@ private:
                     for (const auto& title_id : user_id->GetSubdirectories()) {
                         if (!title_id->GetFiles().empty() ||
                             !title_id->GetSubdirectories().empty()) {
+                            auto user_id_numeric =
+                                Common::HexStringToArray<0x10>(user_id->GetName());
+                            std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
                             info.emplace_back(SaveDataInfo{
                                 0,
                                 space,
                                 FileSys::SaveDataType::TemporaryStorage,
                                 {},
-                                Common::HexStringToArray<0x10, true>(user_id->GetName()),
+                                user_id_numeric,
                                 stoull_be(type->GetName()),
                                 stoull_be(title_id->GetName()),
                                 title_id->GetSize(),

+ 63 - 1
src/core/hle/service/ns/ns.cpp

@@ -2,6 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/logging/log.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
             {305, nullptr, "TerminateSystemApplet"},
             {306, nullptr, "LaunchOverlayApplet"},
             {307, nullptr, "TerminateOverlayApplet"},
-            {400, nullptr, "GetApplicationControlData"},
+            {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
             {401, nullptr, "InvalidateAllApplicationControlCache"},
             {402, nullptr, "RequestDownloadApplicationControlData"},
             {403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
 
         RegisterHandlers(functions);
     }
+
+    void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto flag = rp.PopRaw<u64>();
+        LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
+
+        const auto title_id = rp.PopRaw<u64>();
+
+        const auto size = ctx.GetWriteBufferSize();
+
+        const FileSys::PatchManager pm{title_id};
+        const auto control = pm.GetControlMetadata();
+
+        std::vector<u8> out;
+
+        if (control.first != nullptr) {
+            if (size < 0x4000) {
+                LOG_ERROR(Service_NS,
+                          "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
+                          size);
+                IPC::ResponseBuilder rb{ctx, 2};
+                // TODO(DarkLordZach): Find a better error code for this.
+                rb.Push(ResultCode(-1));
+                return;
+            }
+
+            out.resize(0x4000);
+            const auto bytes = control.first->GetRawBytes();
+            std::memcpy(out.data(), bytes.data(), bytes.size());
+        } else {
+            LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
+                        title_id);
+            out.resize(std::min<u64>(0x4000, size));
+        }
+
+        if (control.second != nullptr) {
+            if (size < 0x4000 + control.second->GetSize()) {
+                LOG_ERROR(Service_NS,
+                          "output buffer is too small! (actual={:016X}, expected_min={:016X})",
+                          size, 0x4000 + control.second->GetSize());
+                IPC::ResponseBuilder rb{ctx, 2};
+                // TODO(DarkLordZach): Find a better error code for this.
+                rb.Push(ResultCode(-1));
+                return;
+            }
+
+            out.resize(0x4000 + control.second->GetSize());
+            control.second->Read(out.data() + 0x4000, control.second->GetSize());
+        } else {
+            LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
+                        title_id);
+        }
+
+        ctx.WriteBuffer(out);
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push<u32>(static_cast<u32>(out.size()));
+    }
 };
 
 class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {