nfp: Validate amiibo files
This commit is contained in:
		| @@ -108,7 +108,7 @@ void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | |||||||
|  |  | ||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
|         const auto result = nfp_interface.StartDetection(); |         const auto result = nfp_interface.StartDetection(nfp_protocol); | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(result); |         rb.Push(result); | ||||||
|         return; |         return; | ||||||
| @@ -209,7 +209,6 @@ void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) { | |||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
|         std::vector<u8> data{}; |         std::vector<u8> data{}; | ||||||
|         const auto result = nfp_interface.GetApplicationArea(data); |         const auto result = nfp_interface.GetApplicationArea(data); | ||||||
|  |  | ||||||
|         ctx.WriteBuffer(data); |         ctx.WriteBuffer(data); | ||||||
|         IPC::ResponseBuilder rb{ctx, 3}; |         IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|         rb.Push(result); |         rb.Push(result); | ||||||
| @@ -232,7 +231,6 @@ void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) { | |||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
|         const auto result = nfp_interface.SetApplicationArea(data); |         const auto result = nfp_interface.SetApplicationArea(data); | ||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(result); |         rb.Push(result); | ||||||
|         return; |         return; | ||||||
| @@ -255,7 +253,6 @@ void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) { | |||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
|         const auto result = nfp_interface.CreateApplicationArea(access_id, data); |         const auto result = nfp_interface.CreateApplicationArea(access_id, data); | ||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(result); |         rb.Push(result); | ||||||
|         return; |         return; | ||||||
| @@ -390,7 +387,7 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void IUser::GetState(Kernel::HLERequestContext& ctx) { | void IUser::GetState(Kernel::HLERequestContext& ctx) { | ||||||
|     LOG_INFO(Service_NFC, "called"); |     LOG_DEBUG(Service_NFC, "called"); | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3, 0}; |     IPC::ResponseBuilder rb{ctx, 3, 0}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| @@ -400,7 +397,7 @@ void IUser::GetState(Kernel::HLERequestContext& ctx) { | |||||||
| void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto device_handle{rp.Pop<u64>()}; |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||||
|  |  | ||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
| @@ -419,7 +416,7 @@ void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | |||||||
| void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto device_handle{rp.Pop<u64>()}; |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||||
|  |  | ||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
| @@ -438,7 +435,7 @@ void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | |||||||
| void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { | void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto device_handle{rp.Pop<u64>()}; |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||||
|  |  | ||||||
|     // TODO(german77): Loop through all interfaces |     // TODO(german77): Loop through all interfaces | ||||||
|     if (device_handle == nfp_interface.GetHandle()) { |     if (device_handle == nfp_interface.GetHandle()) { | ||||||
| @@ -493,6 +490,11 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||||||
|  |  | ||||||
|     LOG_INFO(Service_NFP, "New Amiibo detected"); |     LOG_INFO(Service_NFP, "New Amiibo detected"); | ||||||
|     std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |     std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | ||||||
|  |  | ||||||
|  |     if (!IsAmiiboValid()) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     device_state = DeviceState::TagFound; |     device_state = DeviceState::TagFound; | ||||||
|     activate_event->GetWritableEvent().Signal(); |     activate_event->GetWritableEvent().Signal(); | ||||||
|     return true; |     return true; | ||||||
| @@ -501,13 +503,54 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||||||
| void Module::Interface::CloseAmiibo() { | void Module::Interface::CloseAmiibo() { | ||||||
|     LOG_INFO(Service_NFP, "Remove amiibo"); |     LOG_INFO(Service_NFP, "Remove amiibo"); | ||||||
|     device_state = DeviceState::TagRemoved; |     device_state = DeviceState::TagRemoved; | ||||||
|     write_counter = 0; |  | ||||||
|     is_application_area_initialized = false; |     is_application_area_initialized = false; | ||||||
|     application_area_id = 0; |     application_area_id = 0; | ||||||
|     application_area_data.clear(); |     application_area_data.clear(); | ||||||
|     deactivate_event->GetWritableEvent().Signal(); |     deactivate_event->GetWritableEvent().Signal(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool Module::Interface::IsAmiiboValid() const { | ||||||
|  |     LOG_INFO(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock); | ||||||
|  |     LOG_INFO(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container); | ||||||
|  |     LOG_INFO(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init); | ||||||
|  |     LOG_INFO(Service_NFP, "write_count={}", amiibo.write_count); | ||||||
|  |  | ||||||
|  |     LOG_INFO(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id); | ||||||
|  |     LOG_INFO(Service_NFP, "character_variant={}", amiibo.model_info.character_variant); | ||||||
|  |     LOG_INFO(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type); | ||||||
|  |     LOG_INFO(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number); | ||||||
|  |     LOG_INFO(Service_NFP, "series={}", amiibo.model_info.series); | ||||||
|  |     LOG_INFO(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed); | ||||||
|  |  | ||||||
|  |     LOG_INFO(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock); | ||||||
|  |     LOG_INFO(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0); | ||||||
|  |     LOG_INFO(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1); | ||||||
|  |  | ||||||
|  |     // Check against all know constants on an amiibo binary | ||||||
|  |     if (amiibo.uuid_lock != 0xE00F) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (amiibo.compability_container != 0xEEFF10F1UL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if ((amiibo.crypto_init & 0xFF) != 0xA5) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (amiibo.model_info.fixed != 0x02) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (amiibo.tag_CFG0 != 0x04000000UL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (amiibo.tag_CFG1 != 0x5F) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { | Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { | ||||||
|     return activate_event->GetReadableEvent(); |     return activate_event->GetReadableEvent(); | ||||||
| } | } | ||||||
| @@ -522,13 +565,12 @@ void Module::Interface::Initialize() { | |||||||
|  |  | ||||||
| void Module::Interface::Finalize() { | void Module::Interface::Finalize() { | ||||||
|     device_state = DeviceState::Unaviable; |     device_state = DeviceState::Unaviable; | ||||||
|     write_counter = 0; |  | ||||||
|     is_application_area_initialized = false; |     is_application_area_initialized = false; | ||||||
|     application_area_id = 0; |     application_area_id = 0; | ||||||
|     application_area_data.clear(); |     application_area_data.clear(); | ||||||
| } | } | ||||||
|  |  | ||||||
| ResultCode Module::Interface::StartDetection() { | ResultCode Module::Interface::StartDetection(s32 protocol_) { | ||||||
|     auto npad_device = system.HIDCore().GetEmulatedController(npad_id); |     auto npad_device = system.HIDCore().GetEmulatedController(npad_id); | ||||||
|  |  | ||||||
|     // TODO(german77): Add callback for when nfc data is available |     // TODO(german77): Add callback for when nfc data is available | ||||||
| @@ -536,6 +578,7 @@ ResultCode Module::Interface::StartDetection() { | |||||||
|     if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { |     if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | ||||||
|         npad_device->SetPollingMode(Common::Input::PollingMode::NFC); |         npad_device->SetPollingMode(Common::Input::PollingMode::NFC); | ||||||
|         device_state = DeviceState::SearchingForTag; |         device_state = DeviceState::SearchingForTag; | ||||||
|  |         protocol = protocol_; | ||||||
|         return ResultSuccess; |         return ResultSuccess; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -589,8 +632,8 @@ ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { | |||||||
|         tag_info = { |         tag_info = { | ||||||
|             .uuid = amiibo.uuid, |             .uuid = amiibo.uuid, | ||||||
|             .uuid_length = static_cast<u8>(amiibo.uuid.size()), |             .uuid_length = static_cast<u8>(amiibo.uuid.size()), | ||||||
|             .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values |             .protocol = protocol, | ||||||
|             .tag_type = 0xFFFFFFFF, |             .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type), | ||||||
|         }; |         }; | ||||||
|         return ResultSuccess; |         return ResultSuccess; | ||||||
|     } |     } | ||||||
| @@ -610,7 +653,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { | |||||||
|         .last_write_year = 2022, |         .last_write_year = 2022, | ||||||
|         .last_write_month = 2, |         .last_write_month = 2, | ||||||
|         .last_write_day = 7, |         .last_write_day = 7, | ||||||
|         .write_counter = write_counter, |         .write_counter = amiibo.write_count, | ||||||
|         .version = 1, |         .version = 1, | ||||||
|         .application_area_size = ApplicationAreaSize, |         .application_area_size = ApplicationAreaSize, | ||||||
|     }; |     }; | ||||||
| @@ -652,11 +695,11 @@ ResultCode Module::Interface::OpenApplicationArea(u32 access_id) { | |||||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||||
|         return ErrCodes::WrongDeviceState; |         return ErrCodes::WrongDeviceState; | ||||||
|     } |     } | ||||||
|     // if (AmiiboApplicationDataExist(access_id)) { |     if (AmiiboApplicationDataExist(access_id)) { | ||||||
|     //    application_area_data = LoadAmiiboApplicationData(access_id); |         application_area_data = LoadAmiiboApplicationData(access_id); | ||||||
|     //    application_area_id = access_id; |         application_area_id = access_id; | ||||||
|     //    is_application_area_initialized = true; |         is_application_area_initialized = true; | ||||||
|     // } |     } | ||||||
|     if (!is_application_area_initialized) { |     if (!is_application_area_initialized) { | ||||||
|         LOG_ERROR(Service_NFP, "Application area is not initialized"); |         LOG_ERROR(Service_NFP, "Application area is not initialized"); | ||||||
|         return ErrCodes::ApplicationAreaIsNotInitialized; |         return ErrCodes::ApplicationAreaIsNotInitialized; | ||||||
| @@ -689,8 +732,7 @@ ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) { | |||||||
|         return ErrCodes::ApplicationAreaIsNotInitialized; |         return ErrCodes::ApplicationAreaIsNotInitialized; | ||||||
|     } |     } | ||||||
|     application_area_data = data; |     application_area_data = data; | ||||||
|     write_counter++; |     SaveAmiiboApplicationData(application_area_id, application_area_data); | ||||||
|     // SaveAmiiboApplicationData(application_area_id,application_area_data); |  | ||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -699,21 +741,32 @@ ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::ve | |||||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||||
|         return ErrCodes::WrongDeviceState; |         return ErrCodes::WrongDeviceState; | ||||||
|     } |     } | ||||||
|     // if (AmiiboApplicationDataExist(access_id)) { |     if (AmiiboApplicationDataExist(access_id)) { | ||||||
|     //    LOG_ERROR(Service_NFP, "Application area already exist"); |         LOG_ERROR(Service_NFP, "Application area already exist"); | ||||||
|     //    return ErrCodes::ApplicationAreaExist; |         return ErrCodes::ApplicationAreaExist; | ||||||
|     // } |     } | ||||||
|     // if (LoadAmiiboApplicationData(access_id,data)) { |  | ||||||
|     //    is_application_area_initialized = true; |  | ||||||
|     //    application_area_id = access_id; |  | ||||||
|     // } |  | ||||||
|     application_area_data = data; |     application_area_data = data; | ||||||
|     application_area_id = access_id; |     application_area_id = access_id; | ||||||
|     write_counter = 0; |     SaveAmiiboApplicationData(application_area_id, application_area_data); | ||||||
|     // SaveAmiiboApplicationData(application_area_id,application_area_data); |  | ||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { | ||||||
|  |     // TODO(german77): Check if file exist | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { | ||||||
|  |     // TODO(german77): Read file | ||||||
|  |     std::vector<u8> data(ApplicationAreaSize); | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Module::Interface::SaveAmiiboApplicationData(u32 access_id, | ||||||
|  |                                                   const std::vector<u8>& data) const { | ||||||
|  |     // TODO(german77): Save file | ||||||
|  | } | ||||||
|  |  | ||||||
| u64 Module::Interface::GetHandle() const { | u64 Module::Interface::GetHandle() const { | ||||||
|     // Generate a handle based of the npad id |     // Generate a handle based of the npad id | ||||||
|     return static_cast<u64>(npad_id); |     return static_cast<u64>(npad_id); | ||||||
|   | |||||||
| @@ -53,11 +53,43 @@ enum class MountTarget : u32 { | |||||||
|     All, |     All, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum class AmiiboType : u8 { | ||||||
|  |     Figure, | ||||||
|  |     Card, | ||||||
|  |     Yarn, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum class AmiiboSeries : u8 { | ||||||
|  |     SuperSmashBros, | ||||||
|  |     SuperMario, | ||||||
|  |     ChibiRobo, | ||||||
|  |     YoshiWoollyWorld, | ||||||
|  |     Splatoon, | ||||||
|  |     AnimalCrossing, | ||||||
|  |     EightBitMario, | ||||||
|  |     Skylanders, | ||||||
|  |     Unknown8, | ||||||
|  |     TheLegendOfZelda, | ||||||
|  |     ShovelKnight, | ||||||
|  |     Unknown11, | ||||||
|  |     Kiby, | ||||||
|  |     Pokemon, | ||||||
|  |     MarioSportsSuperstars, | ||||||
|  |     MonsterHunter, | ||||||
|  |     BoxBoy, | ||||||
|  |     Pikmin, | ||||||
|  |     FireEmblem, | ||||||
|  |     Metroid, | ||||||
|  |     Others, | ||||||
|  |     MegaMan, | ||||||
|  |     Diablo | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct TagInfo { | struct TagInfo { | ||||||
|     std::array<u8, 10> uuid; |     std::array<u8, 10> uuid; | ||||||
|     u8 uuid_length; |     u8 uuid_length; | ||||||
|     INSERT_PADDING_BYTES(0x15); |     INSERT_PADDING_BYTES(0x15); | ||||||
|     u32 protocol; |     s32 protocol; | ||||||
|     u32 tag_type; |     u32 tag_type; | ||||||
|     INSERT_PADDING_BYTES(0x30); |     INSERT_PADDING_BYTES(0x30); | ||||||
| }; | }; | ||||||
| @@ -77,10 +109,13 @@ static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | |||||||
| struct ModelInfo { | struct ModelInfo { | ||||||
|     u16 character_id; |     u16 character_id; | ||||||
|     u8 character_variant; |     u8 character_variant; | ||||||
|     u8 figure_type; |     AmiiboType amiibo_type; | ||||||
|     u16 model_number; |     u16 model_number; | ||||||
|     u8 series; |     AmiiboSeries series; | ||||||
|     INSERT_PADDING_BYTES(0x39); |     u8 fixed;                   // Must be 02 | ||||||
|  |     INSERT_PADDING_BYTES(0x4);  // Unknown | ||||||
|  |     INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash | ||||||
|  |     INSERT_PADDING_BYTES(0x14); // SHA256-HMAC | ||||||
| }; | }; | ||||||
| static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | ||||||
|  |  | ||||||
| @@ -105,11 +140,21 @@ public: | |||||||
|  |  | ||||||
|         struct AmiiboFile { |         struct AmiiboFile { | ||||||
|             std::array<u8, 10> uuid; |             std::array<u8, 10> uuid; | ||||||
|             INSERT_PADDING_BYTES(0x4); // Compability container |             u16 uuid_lock;               // Must be 0F E0 | ||||||
|             INSERT_PADDING_BYTES(0x46); |             u32 compability_container;   // Must be F1 10 FF EE | ||||||
|             ModelInfo model_info; |             u16 crypto_init;             // Must be A5 XX | ||||||
|  |             u16 write_count;             // Number of times the amiibo has been written? | ||||||
|  |             INSERT_PADDING_BYTES(0x20);  // System crypts | ||||||
|  |             INSERT_PADDING_BYTES(0x20);  // SHA256-(HMAC?) hash | ||||||
|  |             ModelInfo model_info;        // This struct is bigger than documentation | ||||||
|  |             INSERT_PADDING_BYTES(0xC);   // SHA256-HMAC | ||||||
|  |             INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer | ||||||
|  |             INSERT_PADDING_BYTES(0x54);  // section 2 encrypted buffer | ||||||
|  |             u32 tag_dynamic_lock;        // Must be 01 00 0F XX | ||||||
|  |             u32 tag_CFG0;                // Must be 00 00 00 04 | ||||||
|  |             u32 tag_CFG1;                // Must be 50 00 00 00 | ||||||
|         }; |         }; | ||||||
|         static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); |         static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size"); | ||||||
|  |  | ||||||
|         void CreateUserInterface(Kernel::HLERequestContext& ctx); |         void CreateUserInterface(Kernel::HLERequestContext& ctx); | ||||||
|         bool LoadAmiibo(const std::vector<u8>& buffer); |         bool LoadAmiibo(const std::vector<u8>& buffer); | ||||||
| @@ -118,7 +163,7 @@ public: | |||||||
|         void Initialize(); |         void Initialize(); | ||||||
|         void Finalize(); |         void Finalize(); | ||||||
|  |  | ||||||
|         ResultCode StartDetection(); |         ResultCode StartDetection(s32 protocol_); | ||||||
|         ResultCode StopDetection(); |         ResultCode StopDetection(); | ||||||
|         ResultCode Mount(); |         ResultCode Mount(); | ||||||
|         ResultCode Unmount(); |         ResultCode Unmount(); | ||||||
| @@ -144,6 +189,12 @@ public: | |||||||
|         std::shared_ptr<Module> module; |         std::shared_ptr<Module> module; | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|  |         /// Validates that the amiibo file is not corrupted | ||||||
|  |         bool IsAmiiboValid() const; | ||||||
|  |         bool AmiiboApplicationDataExist(u32 access_id) const; | ||||||
|  |         const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; | ||||||
|  |         void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; | ||||||
|  |  | ||||||
|         const Core::HID::NpadIdType npad_id; |         const Core::HID::NpadIdType npad_id; | ||||||
|  |  | ||||||
|         DeviceState device_state{DeviceState::Unaviable}; |         DeviceState device_state{DeviceState::Unaviable}; | ||||||
| @@ -151,7 +202,7 @@ public: | |||||||
|         Kernel::KEvent* activate_event; |         Kernel::KEvent* activate_event; | ||||||
|         Kernel::KEvent* deactivate_event; |         Kernel::KEvent* deactivate_event; | ||||||
|         AmiiboFile amiibo{}; |         AmiiboFile amiibo{}; | ||||||
|         u16 write_counter{}; |         s32 protocol; | ||||||
|         bool is_application_area_initialized{}; |         bool is_application_area_initialized{}; | ||||||
|         u32 application_area_id; |         u32 application_area_id; | ||||||
|         std::vector<u8> application_area_data; |         std::vector<u8> application_area_data; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Narr the Reg
					Narr the Reg