forked from eden-emu/eden
		
	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.
This commit is contained in:
		
							parent
							
								
									5ee19add1b
								
							
						
					
					
						commit
						bdaa76c0db
					
				
					 4 changed files with 75 additions and 17 deletions
				
			
		|  | @ -83,7 +83,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr | ||||||
|     return MakeResult<VirtualDir>(std::move(out)); |     return MakeResult<VirtualDir>(std::move(out)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) { | VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const { | ||||||
|     return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space)); |     return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -52,7 +52,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); |     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 GetSaveDataSpaceIdPath(SaveDataSpaceId space); | ||||||
|     static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, |     static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | ||||||
|  |  | ||||||
|  | @ -481,9 +481,9 @@ public: | ||||||
|         // Write the data to memory
 |         // Write the data to memory
 | ||||||
|         ctx.WriteBuffer(begin, range_size); |         ctx.WriteBuffer(begin, range_size); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 4}; |         IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.Push(actual_entries); |         rb.Push<u32>(static_cast<u32>(actual_entries)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -498,15 +498,6 @@ private: | ||||||
|         return Common::swap64(out); |         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) { |     void FindAllSaves(FileSys::SaveDataSpaceId space) { | ||||||
|         const auto save_root = OpenSaveDataSpace(space); |         const auto save_root = OpenSaveDataSpace(space); | ||||||
|         ASSERT(save_root.Succeeded()); |         ASSERT(save_root.Succeeded()); | ||||||
|  | @ -516,8 +507,9 @@ private: | ||||||
|                 for (const auto& save_id : type->GetSubdirectories()) { |                 for (const auto& save_id : type->GetSubdirectories()) { | ||||||
|                     for (const auto& user_id : save_id->GetSubdirectories()) { |                     for (const auto& user_id : save_id->GetSubdirectories()) { | ||||||
|                         const auto save_id_numeric = stoull_be(save_id->GetName()); |                         const auto save_id_numeric = stoull_be(save_id->GetName()); | ||||||
|                         const auto user_id_numeric = |                         auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); | ||||||
|                             ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName())); |                         std::reverse(user_id_numeric.begin(), user_id_numeric.end()); | ||||||
|  | 
 | ||||||
|                         if (save_id_numeric != 0) { |                         if (save_id_numeric != 0) { | ||||||
|                             // System Save Data
 |                             // System Save Data
 | ||||||
|                             info.emplace_back(SaveDataInfo{ |                             info.emplace_back(SaveDataInfo{ | ||||||
|  | @ -560,12 +552,16 @@ private: | ||||||
|                     for (const auto& title_id : user_id->GetSubdirectories()) { |                     for (const auto& title_id : user_id->GetSubdirectories()) { | ||||||
|                         if (!title_id->GetFiles().empty() || |                         if (!title_id->GetFiles().empty() || | ||||||
|                             !title_id->GetSubdirectories().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{ |                             info.emplace_back(SaveDataInfo{ | ||||||
|                                 0, |                                 0, | ||||||
|                                 space, |                                 space, | ||||||
|                                 FileSys::SaveDataType::TemporaryStorage, |                                 FileSys::SaveDataType::TemporaryStorage, | ||||||
|                                 {}, |                                 {}, | ||||||
|                                 Common::HexStringToArray<0x10, true>(user_id->GetName()), |                                 user_id_numeric, | ||||||
|                                 stoull_be(type->GetName()), |                                 stoull_be(type->GetName()), | ||||||
|                                 stoull_be(title_id->GetName()), |                                 stoull_be(title_id->GetName()), | ||||||
|                                 title_id->GetSize(), |                                 title_id->GetSize(), | ||||||
|  |  | ||||||
|  | @ -2,6 +2,9 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // 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/ipc_helpers.h" | ||||||
| #include "core/hle/kernel/hle_ipc.h" | #include "core/hle/kernel/hle_ipc.h" | ||||||
| #include "core/hle/service/ns/ns.h" | #include "core/hle/service/ns/ns.h" | ||||||
|  | @ -118,7 +121,7 @@ public: | ||||||
|             {305, nullptr, "TerminateSystemApplet"}, |             {305, nullptr, "TerminateSystemApplet"}, | ||||||
|             {306, nullptr, "LaunchOverlayApplet"}, |             {306, nullptr, "LaunchOverlayApplet"}, | ||||||
|             {307, nullptr, "TerminateOverlayApplet"}, |             {307, nullptr, "TerminateOverlayApplet"}, | ||||||
|             {400, nullptr, "GetApplicationControlData"}, |             {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, | ||||||
|             {401, nullptr, "InvalidateAllApplicationControlCache"}, |             {401, nullptr, "InvalidateAllApplicationControlCache"}, | ||||||
|             {402, nullptr, "RequestDownloadApplicationControlData"}, |             {402, nullptr, "RequestDownloadApplicationControlData"}, | ||||||
|             {403, nullptr, "GetMaxApplicationControlCacheCount"}, |             {403, nullptr, "GetMaxApplicationControlCacheCount"}, | ||||||
|  | @ -243,6 +246,65 @@ public: | ||||||
| 
 | 
 | ||||||
|         RegisterHandlers(functions); |         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> { | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zach Hilman
						Zach Hilman