mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	service/cecd: Implement mboxlist handling
This commit is contained in:
		
							parent
							
								
									0e8398b51c
								
							
						
					
					
						commit
						7a8477d106
					
				
					 2 changed files with 123 additions and 31 deletions
				
			
		|  | @ -67,9 +67,17 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { | ||||||
|             } |             } | ||||||
|             rb.Push<u32>(0); /// Zero entries
 |             rb.Push<u32>(0); /// Zero entries
 | ||||||
|         } else { |         } else { | ||||||
|  |             constexpr u32 max_entries = 32; /// reasonable value, just over max boxes 24
 | ||||||
|             auto directory = dir_result.Unwrap(); |             auto directory = dir_result.Unwrap(); | ||||||
|  | 
 | ||||||
|  |             /// Actual reading into vector seems to be required for entry count
 | ||||||
|  |             std::vector<FileSys::Entry> entries(max_entries); | ||||||
|  |             const u32 entry_count = directory->backend->Read(max_entries, entries.data()); | ||||||
|  | 
 | ||||||
|  |             LOG_DEBUG(Service_CECD, "Number of entries found in = {}", entry_count); | ||||||
|  | 
 | ||||||
|             rb.Push(RESULT_SUCCESS); |             rb.Push(RESULT_SUCCESS); | ||||||
|             rb.Push<u32>(directory->backend->Read(0, nullptr)); /// Entry count
 |             rb.Push<u32>(entry_count); /// Entry count
 | ||||||
|             directory->backend->Close(); |             directory->backend->Close(); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|  | @ -423,19 +431,49 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { /// DeleteMessa | ||||||
|     const u32 message_id_size = rp.Pop<u32>(); |     const u32 message_id_size = rp.Pop<u32>(); | ||||||
|     auto& message_id_buffer = rp.PopMappedBuffer(); |     auto& message_id_buffer = rp.PopMappedBuffer(); | ||||||
| 
 | 
 | ||||||
|     if (is_outbox) { |     FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); | ||||||
| 
 |     FileSys::Mode mode; | ||||||
|     } else { /// otherwise inbox
 |     mode.write_flag.Assign(1); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.Push(RESULT_SUCCESS); |     switch (path_type) { | ||||||
|  |     case CecDataPathType::CEC_PATH_ROOT_DIR: | ||||||
|  |     case CecDataPathType::CEC_PATH_MBOX_DIR: | ||||||
|  |     case CecDataPathType::CEC_PATH_INBOX_DIR: | ||||||
|  |     case CecDataPathType::CEC_PATH_OUTBOX_DIR: | ||||||
|  |         rb.Push(Service::FS::DeleteDirectoryRecursivelyFromArchive( | ||||||
|  |             cecd->cecd_system_save_data_archive, path)); | ||||||
|  |         break; | ||||||
|  |     default: /// If not directory, then it is a file
 | ||||||
|  |         if (message_id_size == 0) { | ||||||
|  |             rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, path)); | ||||||
|  |         } else { | ||||||
|  |             std::vector<u8> id_buffer(message_id_size); | ||||||
|  |             message_id_buffer.Read(id_buffer.data(), 0, message_id_size); | ||||||
|  | 
 | ||||||
|  |             FileSys::Path message_path; | ||||||
|  |             if (is_outbox) { | ||||||
|  |                 message_path = | ||||||
|  |                     cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, | ||||||
|  |                                                      ncch_program_id, id_buffer) | ||||||
|  |                         .data(); | ||||||
|  |             } else { /// otherwise inbox
 | ||||||
|  |                 message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, | ||||||
|  |                                                                 ncch_program_id, id_buffer) | ||||||
|  |                                    .data(); | ||||||
|  |             } | ||||||
|  |             rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, | ||||||
|  |                                                        message_path)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     rb.PushMappedBuffer(message_id_buffer); |     rb.PushMappedBuffer(message_id_buffer); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_CECD, |     LOG_DEBUG(Service_CECD, | ||||||
|               "called, ncch_program_id={:#010x}, path_type={:#04x}, " |               "called, ncch_program_id={:#010x}, path_type={:#04x}, path={}, " | ||||||
|               "is_outbox={}, message_id_size={:#x}", |               "is_outbox={}, message_id_size={:#x}", | ||||||
|               ncch_program_id, static_cast<u32>(path_type), is_outbox, message_id_size); |               ncch_program_id, static_cast<u32>(path_type), path.AsString(), is_outbox, | ||||||
|  |               message_id_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Update Index/List?
 | void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Update Index/List?
 | ||||||
|  | @ -798,25 +836,28 @@ std::string Module::GetCecCommandAsString(const CecCommand command) const { | ||||||
| 
 | 
 | ||||||
| void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, | void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, | ||||||
|                                 std::vector<u8>& file_buffer) { |                                 std::vector<u8>& file_buffer) { | ||||||
|  |     constexpr u32 max_num_boxes = 24; | ||||||
|  |     constexpr u32 name_size = 16;      /// fixed size 16 characters long
 | ||||||
|  |     constexpr u32 valid_name_size = 8; /// 8 characters are valid, the rest are null
 | ||||||
|     const u32 file_size = file_buffer.size(); |     const u32 file_size = file_buffer.size(); | ||||||
| 
 | 
 | ||||||
|     switch (path_type) { |     switch (path_type) { | ||||||
|     case CecDataPathType::CEC_PATH_MBOX_LIST: { |     case CecDataPathType::CEC_PATH_MBOX_LIST: { | ||||||
|         CecMBoxListHeader mbox_list_header = {}; |         CecMBoxListHeader mbox_list_header = {}; | ||||||
|         CecMBoxListBoxes mbox_list_boxes = {}; |  | ||||||
|         std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); |         std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); | ||||||
|         std::memcpy(&mbox_list_boxes, &file_buffer[0xC], sizeof(CecMBoxListBoxes)); |  | ||||||
| 
 | 
 | ||||||
|         if (file_size != 0x18C) { /// 0x18C CecMBoxListHeader + CecMBoxListBoxes
 |         if (file_size != sizeof(CecMBoxListHeader)) { /// 0x18C
 | ||||||
|             LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); |             LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (mbox_list_header.magic != 0x6868) { /// 'hh'
 |         if (mbox_list_header.magic != 0x6868) { /// 'hh'
 | ||||||
|             if (mbox_list_header.magic == 0) |             if (mbox_list_header.magic == 0 || mbox_list_header.magic == 0xFFFF) { | ||||||
|                 LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is not set"); |                 LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is not set"); | ||||||
|             else |             } else { | ||||||
|                 LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is incorrect: {}", |                 LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is incorrect: {}", | ||||||
|                           mbox_list_header.magic); |                           mbox_list_header.magic); | ||||||
|  |             } | ||||||
|  |             std::memset(&mbox_list_header, 0, sizeof(CecMBoxListHeader)); | ||||||
|             mbox_list_header.magic = 0x6868; |             mbox_list_header.magic = 0x6868; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -832,10 +873,69 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|         if (mbox_list_header.num_boxes > 24) { |         if (mbox_list_header.num_boxes > 24) { | ||||||
|             LOG_DEBUG(Service_CECD, "CecMBoxListHeader number of boxes is too large: {}", |             LOG_DEBUG(Service_CECD, "CecMBoxListHeader number of boxes is too large: {}", | ||||||
|                       mbox_list_header.num_boxes); |                       mbox_list_header.num_boxes); | ||||||
|         } |         } else { | ||||||
|  |             std::vector<u8> name_buffer(name_size); | ||||||
|  |             std::memset(name_buffer.data(), 0, name_size); | ||||||
| 
 | 
 | ||||||
|  |             if (ncch_program_id != 0) { | ||||||
|  |                 std::string name = Common::StringFromFormat("%08x", ncch_program_id); | ||||||
|  |                 std::memcpy(name_buffer.data(), name.data(), name.size()); | ||||||
|  | 
 | ||||||
|  |                 bool already_activated = false; | ||||||
|  |                 for (auto i = 0; i < mbox_list_header.num_boxes; i++) { | ||||||
|  |                     LOG_DEBUG(Service_CECD, "{}", i); | ||||||
|  |                     /// Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null
 | ||||||
|  |                     if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i * name_size], | ||||||
|  |                                     valid_name_size) == 0) { | ||||||
|  |                         LOG_DEBUG(Service_CECD, "Title already activated"); | ||||||
|  |                         already_activated = true; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 if (!already_activated) { | ||||||
|  |                     if (mbox_list_header.num_boxes < max_num_boxes) { /// max boxes
 | ||||||
|  |                         LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", name); | ||||||
|  |                         std::memcpy( | ||||||
|  |                             &mbox_list_header.box_names[mbox_list_header.num_boxes * name_size], | ||||||
|  |                             name_buffer.data(), name_size); | ||||||
|  |                         mbox_list_header.num_boxes++; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { /// ncch_program_id == 0, remove/update activated boxes
 | ||||||
|  |                 /// We need to read the /CEC directory to find out which titles, if any,
 | ||||||
|  |                 /// are activated. The num_of_titles = (total_read_count) - 1, to adjust for
 | ||||||
|  |                 /// the MBoxList____ file that is present in the directory as well.
 | ||||||
|  |                 FileSys::Path root_path( | ||||||
|  |                     GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, 0).data()); | ||||||
|  | 
 | ||||||
|  |                 auto dir_result = | ||||||
|  |                     Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, root_path); | ||||||
|  | 
 | ||||||
|  |                 auto root_dir = dir_result.Unwrap(); | ||||||
|  |                 std::vector<FileSys::Entry> entries(max_num_boxes + 1); // + 1 mboxlist
 | ||||||
|  |                 const u32 entry_count = root_dir->backend->Read(max_num_boxes + 1, entries.data()); | ||||||
|  |                 root_dir->backend->Close(); | ||||||
|  | 
 | ||||||
|  |                 LOG_DEBUG(Service_CECD, "Number of entries found in /CEC = {}", entry_count); | ||||||
|  | 
 | ||||||
|  |                 std::string mbox_list_name("MBoxList____"); | ||||||
|  |                 std::string file_name; | ||||||
|  |                 std::u16string u16_filename; | ||||||
|  | 
 | ||||||
|  |                 /// Loop through entries but don't add mboxlist____ to itself.
 | ||||||
|  |                 for (auto i = 0; i < entry_count; i++) { | ||||||
|  |                     u16_filename = std::u16string(entries[i].filename); | ||||||
|  |                     file_name = Common::UTF16ToUTF8(u16_filename); | ||||||
|  | 
 | ||||||
|  |                     if (mbox_list_name.compare(file_name) != 0) { | ||||||
|  |                         LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", file_name); | ||||||
|  |                         std::memcpy(&mbox_list_header.box_names[16 * mbox_list_header.num_boxes++], | ||||||
|  |                                     file_name.data(), valid_name_size); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); |         std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); | ||||||
|         std::memcpy(&file_buffer[0xC], &mbox_list_boxes, sizeof(CecMBoxListBoxes)); |  | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case CecDataPathType::CEC_PATH_MBOX_INFO: { |     case CecDataPathType::CEC_PATH_MBOX_INFO: { | ||||||
|  |  | ||||||
|  | @ -152,24 +152,17 @@ public: | ||||||
|     static_assert(sizeof(CecMBoxInfoHeader) == 0x60, |     static_assert(sizeof(CecMBoxInfoHeader) == 0x60, | ||||||
|                   "CecMBoxInfoHeader struct has incorrect size."); |                   "CecMBoxInfoHeader struct has incorrect size."); | ||||||
| 
 | 
 | ||||||
|     struct CecMBoxListBoxes { |  | ||||||
|         struct Box { |  | ||||||
|             u32_le ncch_program_id; |  | ||||||
|             u32_le padding; |  | ||||||
|             u64_le padding2; |  | ||||||
|         } box[24]; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(CecMBoxListBoxes) == 0x180, "CecMBoxListBoxes struct has incorrect size."); |  | ||||||
| 
 |  | ||||||
|     struct CecMBoxListHeader { |     struct CecMBoxListHeader { | ||||||
|         u16_le magic; // 0x6868 'hh'
 |         u16_le magic; // 0x6868 'hh'
 | ||||||
|         u16_le padding; |         u16_le padding; | ||||||
|         u16_le version; /// 0x01 00, maybe activated flag?
 |         u16_le version; /// 0x01 00, maybe activated flag?
 | ||||||
|         u16_le padding2; |         u16_le padding2; | ||||||
|         u16_le num_boxes; /// 24 max?
 |         u16_le num_boxes; /// 24 max
 | ||||||
|         u16_le padding3; |         u16_le padding3; | ||||||
|  |         u8 box_names[16 * 24]; /// 16 char names, 24 boxes
 | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(CecMBoxListHeader) == 0xC, "CecMBoxListHeader struct has incorrect size."); |     static_assert(sizeof(CecMBoxListHeader) == 0x18C, | ||||||
|  |                   "CecMBoxListHeader struct has incorrect size."); | ||||||
| 
 | 
 | ||||||
|     struct CecMessageHeader { |     struct CecMessageHeader { | ||||||
|         u16_le magic; // ``
 |         u16_le magic; // ``
 | ||||||
|  | @ -222,7 +215,7 @@ public: | ||||||
|         BitField<1, 1, u32> read;    /// 2
 |         BitField<1, 1, u32> read;    /// 2
 | ||||||
|         BitField<2, 1, u32> write;   /// 4
 |         BitField<2, 1, u32> write;   /// 4
 | ||||||
|         BitField<3, 1, u32> create;  /// 8
 |         BitField<3, 1, u32> create;  /// 8
 | ||||||
|         BitField<4, 1, u32> check;   /// 16
 |         BitField<4, 1, u32> check;   /// 16 maybe validate sig?
 | ||||||
|         BitField<30, 1, u32> unk_flag; |         BitField<30, 1, u32> unk_flag; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | @ -579,13 +572,13 @@ public: | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     const std::vector<u8> cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, |  | ||||||
|                                                      0x26, 0x00, 0x01, 0x00}; |  | ||||||
| 
 |  | ||||||
|     /// String used by cecd for base64 encoding found in the sysmodule disassembly
 |     /// String used by cecd for base64 encoding found in the sysmodule disassembly
 | ||||||
|     const std::string base64_dict = |     const std::string base64_dict = | ||||||
|         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; |         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; | ||||||
| 
 | 
 | ||||||
|  |     const std::vector<u8> cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, | ||||||
|  |                                                      0x26, 0x00, 0x01, 0x00}; | ||||||
|  | 
 | ||||||
|     /// Encoding function used for the message id
 |     /// Encoding function used for the message id
 | ||||||
|     std::string EncodeBase64(const std::vector<u8>& in, const std::string& dictionary) const; |     std::string EncodeBase64(const std::vector<u8>& in, const std::string& dictionary) const; | ||||||
| 
 | 
 | ||||||
|  | @ -594,7 +587,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     std::string GetCecCommandAsString(const CecCommand command) const; |     std::string GetCecCommandAsString(const CecCommand command) const; | ||||||
| 
 | 
 | ||||||
|     // void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id);
 |  | ||||||
|     void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, |     void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, | ||||||
|                             std::vector<u8>& file_buffer); |                             std::vector<u8>& file_buffer); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue