mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Move MiiData to its own namespace and add ChecksummedMiiData (#6824)
* Move mii to own namespace and add checksummed mii data * Fix compile issues * Make mii classes trivial and add cast operator * Fix Android side * Add new line at the end of files. * Make miidata a struct and crc16 a u32_be as per switch code. * Apply suggestions * Change back crc to u16 and set padding to 0.
This commit is contained in:
		
							parent
							
								
									f8b8b6e53c
								
							
						
					
					
						commit
						35e208b447
					
				
					 13 changed files with 308 additions and 133 deletions
				
			
		|  | @ -53,7 +53,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { | ||||||
|     const u32 return_code = static_cast<u32>( |     const u32 return_code = static_cast<u32>( | ||||||
|         env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J"))); |         env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J"))); | ||||||
|     if (return_code == 1) { |     if (return_code == 1) { | ||||||
|         Finalize(return_code, HLE::Applets::MiiData{}); |         Finalize(return_code, Mii::MiiData{}); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -67,6 +67,5 @@ void QtMiiSelector::OpenDialog() { | ||||||
|              dialog.return_code, index); |              dialog.return_code, index); | ||||||
| 
 | 
 | ||||||
|     const auto mii_data = dialog.miis.at(index); |     const auto mii_data = dialog.miis.at(index); | ||||||
|     Finalize(dialog.return_code, |     Finalize(dialog.return_code, dialog.return_code == 0 ? std::move(mii_data) : Mii::MiiData{}); | ||||||
|              dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{}); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ private: | ||||||
|     QVBoxLayout* layout; |     QVBoxLayout* layout; | ||||||
|     QtMiiSelector* mii_selector; |     QtMiiSelector* mii_selector; | ||||||
|     u32 return_code = 0; |     u32 return_code = 0; | ||||||
|     std::vector<HLE::Applets::MiiData> miis; |     std::vector<Mii::MiiData> miis; | ||||||
| 
 | 
 | ||||||
|     friend class QtMiiSelector; |     friend class QtMiiSelector; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -184,6 +184,8 @@ add_library(citra_core STATIC | ||||||
|     hle/kernel/wait_object.h |     hle/kernel/wait_object.h | ||||||
|     hle/lock.cpp |     hle/lock.cpp | ||||||
|     hle/lock.h |     hle/lock.h | ||||||
|  |     hle/mii.h | ||||||
|  |     hle/mii.cpp | ||||||
|     hle/result.h |     hle/result.h | ||||||
|     hle/romfs.cpp |     hle/romfs.cpp | ||||||
|     hle/romfs.h |     hle/romfs.h | ||||||
|  |  | ||||||
|  | @ -11,12 +11,12 @@ | ||||||
| 
 | 
 | ||||||
| namespace Frontend { | namespace Frontend { | ||||||
| 
 | 
 | ||||||
| void MiiSelector::Finalize(u32 return_code, HLE::Applets::MiiData mii) { | void MiiSelector::Finalize(u32 return_code, Mii::MiiData mii) { | ||||||
|     data = {return_code, mii}; |     data = {return_code, mii}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<HLE::Applets::MiiData> LoadMiis() { | std::vector<Mii::MiiData> LoadMiis() { | ||||||
|     std::vector<HLE::Applets::MiiData> miis; |     std::vector<Mii::MiiData> miis; | ||||||
| 
 | 
 | ||||||
|     std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)}; |     std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)}; | ||||||
|     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); |     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); | ||||||
|  | @ -36,7 +36,7 @@ std::vector<HLE::Applets::MiiData> LoadMiis() { | ||||||
|             u32 saved_miis_offset = 0x8; |             u32 saved_miis_offset = 0x8; | ||||||
|             // The Mii Maker has a 100 Mii limit on the 3ds
 |             // The Mii Maker has a 100 Mii limit on the 3ds
 | ||||||
|             for (int i = 0; i < 100; ++i) { |             for (int i = 0; i < 100; ++i) { | ||||||
|                 HLE::Applets::MiiData mii; |                 Mii::MiiData mii; | ||||||
|                 std::array<u8, sizeof(mii)> mii_raw; |                 std::array<u8, sizeof(mii)> mii_raw; | ||||||
|                 file->Read(saved_miis_offset, sizeof(mii), mii_raw.data()); |                 file->Read(saved_miis_offset, sizeof(mii), mii_raw.data()); | ||||||
|                 std::memcpy(&mii, mii_raw.data(), sizeof(mii)); |                 std::memcpy(&mii, mii_raw.data(), sizeof(mii)); | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ struct MiiSelectorConfig { | ||||||
| 
 | 
 | ||||||
| struct MiiSelectorData { | struct MiiSelectorData { | ||||||
|     u32 return_code; |     u32 return_code; | ||||||
|     HLE::Applets::MiiData mii; |     Mii::MiiData mii; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class MiiSelector { | class MiiSelector { | ||||||
|  | @ -43,14 +43,14 @@ public: | ||||||
|      * Stores the data so that the HLE applet in core can |      * Stores the data so that the HLE applet in core can | ||||||
|      * send this to the calling application |      * send this to the calling application | ||||||
|      */ |      */ | ||||||
|     void Finalize(u32 return_code, HLE::Applets::MiiData mii); |     void Finalize(u32 return_code, Mii::MiiData mii); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     MiiSelectorConfig config; |     MiiSelectorConfig config; | ||||||
|     MiiSelectorData data; |     MiiSelectorData data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| std::vector<HLE::Applets::MiiData> LoadMiis(); | std::vector<Mii::MiiData> LoadMiis(); | ||||||
| 
 | 
 | ||||||
| class DefaultMiiSelector final : public MiiSelector { | class DefaultMiiSelector final : public MiiSelector { | ||||||
| public: | public: | ||||||
|  |  | ||||||
|  | @ -71,9 +71,6 @@ void MiiSelector::Update() { | ||||||
|     const MiiSelectorData& data = frontend_applet->ReceiveData(); |     const MiiSelectorData& data = frontend_applet->ReceiveData(); | ||||||
|     result.return_code = data.return_code; |     result.return_code = data.return_code; | ||||||
|     result.selected_mii_data = data.mii; |     result.selected_mii_data = data.mii; | ||||||
|     // Calculate the checksum of the selected Mii, see https://www.3dbrew.org/wiki/Mii#Checksum
 |  | ||||||
|     result.mii_data_checksum = boost::crc<16, 0x1021, 0, 0, false, false>( |  | ||||||
|         &result.selected_mii_data, sizeof(HLE::Applets::MiiData) + sizeof(result.unknown1)); |  | ||||||
|     result.selected_guest_mii_index = 0xFFFFFFFF; |     result.selected_guest_mii_index = 0xFFFFFFFF; | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): We're finalizing the applet immediately after it's started,
 |     // TODO(Subv): We're finalizing the applet immediately after it's started,
 | ||||||
|  | @ -92,29 +89,31 @@ MiiResult MiiSelector::GetStandardMiiResult() { | ||||||
|     // This data was obtained by writing the returned buffer in AppletManager::GlanceParameter of
 |     // This data was obtained by writing the returned buffer in AppletManager::GlanceParameter of
 | ||||||
|     // the LLEd Mii picker of version system version 11.8.0 to a file and then matching the values
 |     // the LLEd Mii picker of version system version 11.8.0 to a file and then matching the values
 | ||||||
|     // to the members of the MiiResult struct
 |     // to the members of the MiiResult struct
 | ||||||
|     MiiData mii_data; |     Mii::MiiData mii_data; | ||||||
|     mii_data.mii_id = 0x03001030; |     mii_data.magic = 0x03; | ||||||
|  |     mii_data.mii_options.raw = 0x00; | ||||||
|  |     mii_data.mii_pos.raw = 0x10; | ||||||
|  |     mii_data.console_identity.raw = 0x30; | ||||||
|     mii_data.system_id = 0xD285B6B300C8850A; |     mii_data.system_id = 0xD285B6B300C8850A; | ||||||
|     mii_data.specialness_and_creation_date = 0x98391EE4; |     mii_data.mii_id = 0x98391EE4; | ||||||
|     mii_data.creator_mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10}; |     mii_data.mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10}; | ||||||
|     mii_data.padding = 0x0; |     mii_data.pad = 0x0000; | ||||||
|     mii_data.mii_information = 0xA600; |     mii_data.mii_details.raw = 0xA600; | ||||||
|     mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0}; |     mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0}; | ||||||
|     mii_data.width_height = 0x4040; |     mii_data.height = 0x40; | ||||||
|     mii_data.appearance_bits1.raw = 0x0; |     mii_data.width = 0x40; | ||||||
|     mii_data.appearance_bits2.raw = 0x0; |     mii_data.face_style.raw = 0x00; | ||||||
|  |     mii_data.face_details.raw = 0x00; | ||||||
|     mii_data.hair_style = 0x21; |     mii_data.hair_style = 0x21; | ||||||
|     mii_data.appearance_bits3.hair_color.Assign(0x1); |     mii_data.hair_details.raw = 0x01; | ||||||
|     mii_data.appearance_bits3.flip_hair.Assign(0x0); |     mii_data.eye_details.raw = 0x02684418; | ||||||
|     mii_data.unknown1 = 0x02684418; |     mii_data.eyebrow_details.raw = 0x26344614; | ||||||
|     mii_data.appearance_bits4.eyebrow_style.Assign(0x6); |     mii_data.nose_details.raw = 0x8112; | ||||||
|     mii_data.appearance_bits4.eyebrow_color.Assign(0x1); |     mii_data.mouth_details.raw = 0x1768; | ||||||
|     mii_data.appearance_bits5.eyebrow_scale.Assign(0x4); |     mii_data.mustache_details.raw = 0x0D00; | ||||||
|     mii_data.appearance_bits5.eyebrow_yscale.Assign(0x3); |     mii_data.beard_details.raw = 0x0029; | ||||||
|     mii_data.appearance_bits6 = 0x4614; |     mii_data.glasses_details.raw = 0x0052; | ||||||
|     mii_data.unknown2 = 0x81121768; |     mii_data.mole_details.raw = 0x4850; | ||||||
|     mii_data.allow_copying = 0x0D; |  | ||||||
|     mii_data.unknown3 = {0x0, 0x0, 0x29, 0x0, 0x52, 0x48, 0x50}; |  | ||||||
|     mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0}; |     mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0}; | ||||||
| 
 | 
 | ||||||
|     MiiResult result; |     MiiResult result; | ||||||
|  | @ -122,8 +121,6 @@ MiiResult MiiSelector::GetStandardMiiResult() { | ||||||
|     result.is_guest_mii_selected = 0x0; |     result.is_guest_mii_selected = 0x0; | ||||||
|     result.selected_guest_mii_index = 0xFFFFFFFF; |     result.selected_guest_mii_index = 0xFFFFFFFF; | ||||||
|     result.selected_mii_data = mii_data; |     result.selected_mii_data = mii_data; | ||||||
|     result.unknown1 = 0x0; |  | ||||||
|     result.mii_data_checksum = 0x056C; |  | ||||||
|     result.guest_mii_name.fill(0x0); |     result.guest_mii_name.fill(0x0); | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/applets/applet.h" | #include "core/hle/applets/applet.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/mii.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/apt/apt.h" | #include "core/hle/service/apt/apt.h" | ||||||
| 
 | 
 | ||||||
|  | @ -44,65 +45,11 @@ ASSERT_REG_POSITION(initially_selected_mii_index, 0x90); | ||||||
| ASSERT_REG_POSITION(guest_mii_whitelist, 0x94); | ASSERT_REG_POSITION(guest_mii_whitelist, 0x94); | ||||||
| #undef ASSERT_REG_POSITION | #undef ASSERT_REG_POSITION | ||||||
| 
 | 
 | ||||||
| #pragma pack(push, 1) |  | ||||||
| struct MiiData { |  | ||||||
|     u32_be mii_id; |  | ||||||
|     u64_be system_id; |  | ||||||
|     u32_be specialness_and_creation_date; |  | ||||||
|     std::array<u8, 0x6> creator_mac; |  | ||||||
|     u16_be padding; |  | ||||||
|     u16_be mii_information; |  | ||||||
|     std::array<u16_le, 0xA> mii_name; |  | ||||||
|     u16_be width_height; |  | ||||||
|     union { |  | ||||||
|         u8 raw; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 1, u8> disable_sharing; |  | ||||||
|         BitField<1, 4, u8> face_shape; |  | ||||||
|         BitField<5, 3, u8> skin_color; |  | ||||||
|     } appearance_bits1; |  | ||||||
|     union { |  | ||||||
|         u8 raw; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 4, u8> wrinkles; |  | ||||||
|         BitField<4, 4, u8> makeup; |  | ||||||
|     } appearance_bits2; |  | ||||||
|     u8 hair_style; |  | ||||||
|     union { |  | ||||||
|         u8 raw; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 3, u8> hair_color; |  | ||||||
|         BitField<3, 1, u8> flip_hair; |  | ||||||
|     } appearance_bits3; |  | ||||||
|     u32_be unknown1; |  | ||||||
|     union { |  | ||||||
|         u8 raw; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 5, u8> eyebrow_style; |  | ||||||
|         BitField<5, 3, u8> eyebrow_color; |  | ||||||
|     } appearance_bits4; |  | ||||||
|     union { |  | ||||||
|         u8 raw; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 4, u8> eyebrow_scale; |  | ||||||
|         BitField<4, 3, u8> eyebrow_yscale; |  | ||||||
|     } appearance_bits5; |  | ||||||
|     u16_be appearance_bits6; |  | ||||||
|     u32_be unknown2; |  | ||||||
|     u8 allow_copying; |  | ||||||
|     std::array<u8, 0x7> unknown3; |  | ||||||
|     std::array<u16_le, 0xA> author_name; |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); |  | ||||||
| #pragma pack(pop) |  | ||||||
| 
 |  | ||||||
| struct MiiResult { | struct MiiResult { | ||||||
|     u32_be return_code; |     u32_be return_code; | ||||||
|     u32_be is_guest_mii_selected; |     u32_be is_guest_mii_selected; | ||||||
|     u32_be selected_guest_mii_index; |     u32_be selected_guest_mii_index; | ||||||
|     MiiData selected_mii_data; |     Mii::ChecksummedMiiData selected_mii_data; | ||||||
|     u16_be unknown1; |  | ||||||
|     u16_be mii_data_checksum; |  | ||||||
|     std::array<u16_le, 0xC> guest_mii_name; |     std::array<u16_le, 0xC> guest_mii_name; | ||||||
| }; | }; | ||||||
| static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); | static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								src/core/hle/mii.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/core/hle/mii.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | // Copyright 2023 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <boost/crc.hpp> | ||||||
|  | #include "core/hle/mii.h" | ||||||
|  | 
 | ||||||
|  | namespace Mii { | ||||||
|  | u16 ChecksummedMiiData::CalculateChecksum() { | ||||||
|  |     // Calculate the checksum of the selected Mii, see https://www.3dbrew.org/wiki/Mii#Checksum
 | ||||||
|  |     return boost::crc<16, 0x1021, 0, 0, false, false>(this, offsetof(ChecksummedMiiData, crc16)); | ||||||
|  | } | ||||||
|  | } // namespace Mii
 | ||||||
							
								
								
									
										239
									
								
								src/core/hle/mii.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/core/hle/mii.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,239 @@ | ||||||
|  | // Copyright 2023 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <boost/serialization/base_object.hpp> | ||||||
|  | #include <boost/serialization/binary_object.hpp> | ||||||
|  | #include "common/bit_field.h" | ||||||
|  | #include "common/common_types.h" | ||||||
|  | 
 | ||||||
|  | namespace Mii { | ||||||
|  | 
 | ||||||
|  | #pragma pack(push, 1) | ||||||
|  | // Reference: https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/mii.h
 | ||||||
|  | struct MiiData { | ||||||
|  |     u8 magic; ///< Always 3?
 | ||||||
|  | 
 | ||||||
|  |     /// Mii options
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 1, u8> allow_copying;   ///< True if copying is allowed
 | ||||||
|  |         BitField<1, 1, u8> is_private_name; ///< Private name?
 | ||||||
|  |         BitField<2, 2, u8> region_lock;     ///< Region lock (0=no lock, 1=JPN, 2=USA, 3=EUR)
 | ||||||
|  |         BitField<4, 2, u8> char_set;        ///< Character set (0=JPN+USA+EUR, 1=CHN, 2=KOR, 3=TWN)
 | ||||||
|  |     } mii_options; | ||||||
|  | 
 | ||||||
|  |     /// Mii position in Mii selector or Mii maker
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 4, u8> page_index; ///< Page index of Mii
 | ||||||
|  |         BitField<4, 4, u8> slot_index; ///< Slot offset of Mii on its Page
 | ||||||
|  |     } mii_pos; | ||||||
|  | 
 | ||||||
|  |     /// Console Identity
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 4, u8> unknown0; ///< Mabye padding (always seems to be 0)?
 | ||||||
|  |         BitField<4, 3, u8> | ||||||
|  |             origin_console; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS)
 | ||||||
|  |     } console_identity; | ||||||
|  | 
 | ||||||
|  |     u64_be system_id;      ///< Identifies the system that the Mii was created on (Determines pants)
 | ||||||
|  |     u32_be mii_id;         ///< ID of Mii
 | ||||||
|  |     std::array<u8, 6> mac; ///< Creator's system's full MAC address
 | ||||||
|  |     u16 pad;               ///< Padding
 | ||||||
|  | 
 | ||||||
|  |     /// Mii details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 1, u16> sex;          ///< Sex of Mii (False=Male, True=Female)
 | ||||||
|  |         BitField<1, 4, u16> bday_month;   ///< Month of Mii's birthday
 | ||||||
|  |         BitField<5, 5, u16> bday_day;     ///< Day of Mii's birthday
 | ||||||
|  |         BitField<10, 4, u16> shirt_color; ///< Color of Mii's shirt
 | ||||||
|  |         BitField<14, 1, u16> favorite;    ///< Whether the Mii is one of your 10 favorite Mii's
 | ||||||
|  |     } mii_details; | ||||||
|  | 
 | ||||||
|  |     std::array<u16_le, 10> mii_name; ///< Name of Mii (Encoded using UTF16)
 | ||||||
|  |     u8 height;                       ///< How tall the Mii is
 | ||||||
|  |     u8 width;                        ///< How wide the Mii is
 | ||||||
|  | 
 | ||||||
|  |     /// Face style
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 1, u8> disable_sharing; ///< Whether or not Sharing of the Mii is allowed
 | ||||||
|  |         BitField<1, 4, u8> shape;           ///< Face shape
 | ||||||
|  |         BitField<5, 3, u8> skin_color;      ///< Color of skin
 | ||||||
|  |     } face_style; | ||||||
|  | 
 | ||||||
|  |     /// Face details
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 4, u8> wrinkles; | ||||||
|  |         BitField<4, 4, u8> makeup; | ||||||
|  |     } face_details; | ||||||
|  | 
 | ||||||
|  |     u8 hair_style; | ||||||
|  | 
 | ||||||
|  |     /// Hair details
 | ||||||
|  |     union { | ||||||
|  |         u8 raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 3, u8> color; | ||||||
|  |         BitField<3, 1, u8> flip; | ||||||
|  |     } hair_details; | ||||||
|  | 
 | ||||||
|  |     /// Eye details
 | ||||||
|  |     union { | ||||||
|  |         u32_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 6, u32> style; | ||||||
|  |         BitField<6, 3, u32> color; | ||||||
|  |         BitField<9, 4, u32> scale; | ||||||
|  |         BitField<13, 3, u32> y_scale; | ||||||
|  |         BitField<16, 5, u32> rotation; | ||||||
|  |         BitField<21, 4, u32> x_spacing; | ||||||
|  |         BitField<25, 5, u32> y_position; | ||||||
|  |     } eye_details; | ||||||
|  | 
 | ||||||
|  |     /// Eyebrow details
 | ||||||
|  |     union { | ||||||
|  |         u32_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 5, u32> style; | ||||||
|  |         BitField<5, 3, u32> color; | ||||||
|  |         BitField<8, 4, u32> scale; | ||||||
|  |         BitField<12, 3, u32> y_scale; | ||||||
|  |         BitField<15, 1, u32> pad; | ||||||
|  |         BitField<16, 5, u32> rotation; | ||||||
|  |         BitField<21, 4, u32> x_spacing; | ||||||
|  |         BitField<25, 5, u32> y_position; | ||||||
|  |     } eyebrow_details; | ||||||
|  | 
 | ||||||
|  |     /// Nose details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 5, u16> style; | ||||||
|  |         BitField<5, 4, u16> scale; | ||||||
|  |         BitField<9, 5, u16> y_position; | ||||||
|  |     } nose_details; | ||||||
|  | 
 | ||||||
|  |     /// Mouth details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 6, u16> style; | ||||||
|  |         BitField<6, 3, u16> color; | ||||||
|  |         BitField<9, 4, u16> scale; | ||||||
|  |         BitField<13, 3, u16> y_scale; | ||||||
|  |     } mouth_details; | ||||||
|  | 
 | ||||||
|  |     /// Mustache details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 5, u16> mouth_yposition; | ||||||
|  |         BitField<5, 3, u16> mustach_style; | ||||||
|  |         BitField<8, 2, u16> pad; | ||||||
|  |     } mustache_details; | ||||||
|  | 
 | ||||||
|  |     /// Beard details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 3, u16> style; | ||||||
|  |         BitField<3, 3, u16> color; | ||||||
|  |         BitField<6, 4, u16> scale; | ||||||
|  |         BitField<10, 5, u16> y_pos; | ||||||
|  |     } beard_details; | ||||||
|  | 
 | ||||||
|  |     /// Glasses details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 4, u16> style; | ||||||
|  |         BitField<4, 3, u16> color; | ||||||
|  |         BitField<7, 4, u16> scale; | ||||||
|  |         BitField<11, 5, u16> y_pos; | ||||||
|  |     } glasses_details; | ||||||
|  | 
 | ||||||
|  |     /// Mole details
 | ||||||
|  |     union { | ||||||
|  |         u16_be raw; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 1, u16> enable; | ||||||
|  |         BitField<1, 5, u16> scale; | ||||||
|  |         BitField<6, 5, u16> x_pos; | ||||||
|  |         BitField<11, 5, u16> y_pos; | ||||||
|  |     } mole_details; | ||||||
|  | 
 | ||||||
|  |     std::array<u16_le, 10> author_name; ///< Name of Mii's author (Encoded using UTF16)
 | ||||||
|  | private: | ||||||
|  |     template <class Archive> | ||||||
|  |     void serialize(Archive& ar, const unsigned int) { | ||||||
|  |         ar& boost::serialization::make_binary_object(this, sizeof(MiiData)); | ||||||
|  |     } | ||||||
|  |     friend class boost::serialization::access; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); | ||||||
|  | static_assert(std::is_trivial_v<MiiData>, "MiiData must be trivial."); | ||||||
|  | static_assert(std::is_trivially_copyable_v<MiiData>, "MiiData must be trivially copyable."); | ||||||
|  | 
 | ||||||
|  | struct ChecksummedMiiData { | ||||||
|  | private: | ||||||
|  |     MiiData mii_data; | ||||||
|  |     u16 padding; | ||||||
|  |     u16_be crc16; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     ChecksummedMiiData& operator=(const MiiData& data) { | ||||||
|  |         mii_data = data; | ||||||
|  |         padding = 0; | ||||||
|  |         FixChecksum(); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ChecksummedMiiData& operator=(MiiData&& data) { | ||||||
|  |         mii_data = std::move(data); | ||||||
|  |         padding = 0; | ||||||
|  |         FixChecksum(); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     operator MiiData() const { | ||||||
|  |         return mii_data; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool IsChecksumValid() { | ||||||
|  |         return crc16 == CalculateChecksum(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u16 CalculateChecksum(); | ||||||
|  | 
 | ||||||
|  |     void FixChecksum() { | ||||||
|  |         crc16 = CalculateChecksum(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     template <class Archive> | ||||||
|  |     void serialize(Archive& ar, const unsigned int) { | ||||||
|  |         ar& boost::serialization::make_binary_object(this, sizeof(ChecksummedMiiData)); | ||||||
|  |     } | ||||||
|  |     friend class boost::serialization::access; | ||||||
|  | }; | ||||||
|  | #pragma pack(pop) | ||||||
|  | static_assert(sizeof(ChecksummedMiiData) == 0x60, | ||||||
|  |               "ChecksummedMiiData structure has incorrect size"); | ||||||
|  | static_assert(std::is_trivial_v<ChecksummedMiiData>, "ChecksummedMiiData must be trivial."); | ||||||
|  | static_assert(std::is_trivially_copyable_v<ChecksummedMiiData>, | ||||||
|  |               "ChecksummedMiiData must be trivially copyable."); | ||||||
|  | } // namespace Mii
 | ||||||
|  | @ -86,8 +86,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | ||||||
|     encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version; |     encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version; | ||||||
|     encoded_data.settings = nfc_data.user_memory.settings; |     encoded_data.settings = nfc_data.user_memory.settings; | ||||||
|     encoded_data.owner_mii = nfc_data.user_memory.owner_mii; |     encoded_data.owner_mii = nfc_data.user_memory.owner_mii; | ||||||
|     encoded_data.padding = nfc_data.user_memory.padding; |  | ||||||
|     encoded_data.owner_mii_aes_ccm = nfc_data.user_memory.owner_mii_aes_ccm; |  | ||||||
|     encoded_data.application_id = nfc_data.user_memory.application_id; |     encoded_data.application_id = nfc_data.user_memory.application_id; | ||||||
|     encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter; |     encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter; | ||||||
|     encoded_data.application_area_id = nfc_data.user_memory.application_area_id; |     encoded_data.application_area_id = nfc_data.user_memory.application_area_id; | ||||||
|  | @ -123,8 +121,6 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | ||||||
|     nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version; |     nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version; | ||||||
|     nfc_data.user_memory.settings = encoded_data.settings; |     nfc_data.user_memory.settings = encoded_data.settings; | ||||||
|     nfc_data.user_memory.owner_mii = encoded_data.owner_mii; |     nfc_data.user_memory.owner_mii = encoded_data.owner_mii; | ||||||
|     nfc_data.user_memory.padding = encoded_data.padding; |  | ||||||
|     nfc_data.user_memory.owner_mii_aes_ccm = encoded_data.owner_mii_aes_ccm; |  | ||||||
|     nfc_data.user_memory.application_id = encoded_data.application_id; |     nfc_data.user_memory.application_id = encoded_data.application_id; | ||||||
|     nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter; |     nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter; | ||||||
|     nfc_data.user_memory.application_area_id = encoded_data.application_area_id; |     nfc_data.user_memory.application_area_id = encoded_data.application_area_id; | ||||||
|  |  | ||||||
|  | @ -539,7 +539,6 @@ ResultCode NfcDevice::GetRegisterInfo(RegisterInfo& register_info) const { | ||||||
|     // TODO: Validate this data
 |     // TODO: Validate this data
 | ||||||
|     register_info = { |     register_info = { | ||||||
|         .mii_data = tag.file.owner_mii, |         .mii_data = tag.file.owner_mii, | ||||||
|         .owner_mii_aes_ccm = tag.file.owner_mii_aes_ccm, |  | ||||||
|         .amiibo_name = settings.amiibo_name, |         .amiibo_name = settings.amiibo_name, | ||||||
|         .flags = static_cast<u8>(settings.settings.raw & 0xf), |         .flags = static_cast<u8>(settings.settings.raw & 0xf), | ||||||
|         .font_region = settings.country_code_id, |         .font_region = settings.country_code_id, | ||||||
|  | @ -628,8 +627,7 @@ ResultCode NfcDevice::DeleteRegisterInfo() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     CryptoPP::AutoSeededRandomPool rng; |     CryptoPP::AutoSeededRandomPool rng; | ||||||
|     const std::size_t mii_data_size = |     const std::size_t mii_data_size = sizeof(tag.file.owner_mii); | ||||||
|         sizeof(tag.file.owner_mii) + sizeof(tag.file.padding) + sizeof(tag.file.owner_mii_aes_ccm); |  | ||||||
|     std::array<CryptoPP::byte, mii_data_size> buffer{}; |     std::array<CryptoPP::byte, mii_data_size> buffer{}; | ||||||
|     rng.GenerateBlock(buffer.data(), mii_data_size); |     rng.GenerateBlock(buffer.data(), mii_data_size); | ||||||
| 
 | 
 | ||||||
|  | @ -664,12 +662,9 @@ ResultCode NfcDevice::SetRegisterInfoPrivate(const RegisterInfoPrivate& register | ||||||
|         settings.write_date = GetAmiiboDate(); |         settings.write_date = GetAmiiboDate(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Calculate mii CRC with the padding
 |  | ||||||
|     tag.file.owner_mii_aes_ccm = boost::crc<16, 0x1021, 0, 0, false, false>( |  | ||||||
|         ®ister_info.mii_data, sizeof(HLE::Applets::MiiData) + sizeof(u16)); |  | ||||||
| 
 |  | ||||||
|     settings.amiibo_name = register_info.amiibo_name; |     settings.amiibo_name = register_info.amiibo_name; | ||||||
|     tag.file.owner_mii = register_info.mii_data; |     tag.file.owner_mii = register_info.mii_data; | ||||||
|  |     tag.file.owner_mii.FixChecksum(); | ||||||
|     tag.file.mii_extension = {}; |     tag.file.mii_extension = {}; | ||||||
|     tag.file.unknown = 0; |     tag.file.unknown = 0; | ||||||
|     tag.file.unknown2 = {}; |     tag.file.unknown2 = {}; | ||||||
|  | @ -1061,9 +1056,7 @@ void NfcDevice::UpdateSettingsCrc() { | ||||||
| void NfcDevice::UpdateRegisterInfoCrc() { | void NfcDevice::UpdateRegisterInfoCrc() { | ||||||
| #pragma pack(push, 1) | #pragma pack(push, 1) | ||||||
|     struct CrcData { |     struct CrcData { | ||||||
|         HLE::Applets::MiiData mii; |         Mii::ChecksummedMiiData mii; | ||||||
|         INSERT_PADDING_BYTES(0x2); |  | ||||||
|         u16 mii_crc; |  | ||||||
|         u8 application_id_byte; |         u8 application_id_byte; | ||||||
|         u8 unknown; |         u8 unknown; | ||||||
|         u64 mii_extension; |         u64 mii_extension; | ||||||
|  | @ -1074,7 +1067,6 @@ void NfcDevice::UpdateRegisterInfoCrc() { | ||||||
| 
 | 
 | ||||||
|     const CrcData crc_data{ |     const CrcData crc_data{ | ||||||
|         .mii = tag.file.owner_mii, |         .mii = tag.file.owner_mii, | ||||||
|         .mii_crc = tag.file.owner_mii_aes_ccm, |  | ||||||
|         .application_id_byte = tag.file.application_id_byte, |         .application_id_byte = tag.file.application_id_byte, | ||||||
|         .unknown = tag.file.unknown, |         .unknown = tag.file.unknown, | ||||||
|         .mii_extension = tag.file.mii_extension, |         .mii_extension = tag.file.mii_extension, | ||||||
|  | @ -1102,8 +1094,6 @@ void NfcDevice::BuildAmiiboWithoutKeys() { | ||||||
|     settings.settings.font_region.Assign(0); |     settings.settings.font_region.Assign(0); | ||||||
|     settings.init_date = GetAmiiboDate(); |     settings.init_date = GetAmiiboDate(); | ||||||
|     tag.file.owner_mii = default_mii.selected_mii_data; |     tag.file.owner_mii = default_mii.selected_mii_data; | ||||||
|     tag.file.padding = default_mii.unknown1; |  | ||||||
|     tag.file.owner_mii_aes_ccm = default_mii.mii_data_checksum; |  | ||||||
| 
 | 
 | ||||||
|     // Admin info
 |     // Admin info
 | ||||||
|     settings.settings.amiibo_initialized.Assign(1); |     settings.settings.amiibo_initialized.Assign(1); | ||||||
|  |  | ||||||
|  | @ -269,20 +269,18 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz | ||||||
| 
 | 
 | ||||||
| #pragma pack(1) | #pragma pack(1) | ||||||
| struct EncryptedAmiiboFile { | struct EncryptedAmiiboFile { | ||||||
|     u8 constant_value;                // Must be A5
 |     u8 constant_value;                 // Must be A5
 | ||||||
|     u16_be write_counter;             // Number of times the amiibo has been written?
 |     u16_be write_counter;              // Number of times the amiibo has been written?
 | ||||||
|     u8 amiibo_version;                // Amiibo file version
 |     u8 amiibo_version;                 // Amiibo file version
 | ||||||
|     AmiiboSettings settings;          // Encrypted amiibo settings
 |     AmiiboSettings settings;           // Encrypted amiibo settings
 | ||||||
|     HashData hmac_tag;                // Hash
 |     HashData hmac_tag;                 // Hash
 | ||||||
|     AmiiboModelInfo model_info;       // Encrypted amiibo model info
 |     AmiiboModelInfo model_info;        // Encrypted amiibo model info
 | ||||||
|     HashData keygen_salt;             // Salt
 |     HashData keygen_salt;              // Salt
 | ||||||
|     HashData hmac_data;               // Hash
 |     HashData hmac_data;                // Hash
 | ||||||
|     HLE::Applets::MiiData owner_mii;  // Encrypted Mii data
 |     Mii::ChecksummedMiiData owner_mii; // Encrypted Mii data
 | ||||||
|     u16 padding;                      // Mii Padding
 |     u64_be application_id;             // Encrypted Game id
 | ||||||
|     u16_be owner_mii_aes_ccm;         // Mii data AES-CCM MAC
 |     u16_be application_write_counter;  // Encrypted Counter
 | ||||||
|     u64_be application_id;            // Encrypted Game id
 |     u32_be application_area_id;        // Encrypted Game id
 | ||||||
|     u16_be application_write_counter; // Encrypted Counter
 |  | ||||||
|     u32_be application_area_id;       // Encrypted Game id
 |  | ||||||
|     u8 application_id_byte; |     u8 application_id_byte; | ||||||
|     u8 unknown; |     u8 unknown; | ||||||
|     u64 mii_extension; |     u64 mii_extension; | ||||||
|  | @ -301,11 +299,9 @@ struct NTAG215File { | ||||||
|     u16_be write_counter;      // Number of times the amiibo has been written?
 |     u16_be write_counter;      // Number of times the amiibo has been written?
 | ||||||
|     u8 amiibo_version;         // Amiibo file version
 |     u8 amiibo_version;         // Amiibo file version
 | ||||||
|     AmiiboSettings settings; |     AmiiboSettings settings; | ||||||
|     HLE::Applets::MiiData owner_mii;  // Mii data
 |     Mii::ChecksummedMiiData owner_mii; // Mii data
 | ||||||
|     u16 padding;                      // Mii Padding
 |     u64_be application_id;             // Game id
 | ||||||
|     u16_be owner_mii_aes_ccm;         // Mii data AES-CCM MAC
 |     u16_be application_write_counter;  // Counter
 | ||||||
|     u64_be application_id;            // Game id
 |  | ||||||
|     u16_be application_write_counter; // Counter
 |  | ||||||
|     u32_be application_area_id; |     u32_be application_area_id; | ||||||
|     u8 application_id_byte; |     u8 application_id_byte; | ||||||
|     u8 unknown; |     u8 unknown; | ||||||
|  | @ -417,9 +413,7 @@ struct ModelInfo { | ||||||
| static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size"); | static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size"); | ||||||
| 
 | 
 | ||||||
| struct RegisterInfo { | struct RegisterInfo { | ||||||
|     HLE::Applets::MiiData mii_data; |     Mii::ChecksummedMiiData mii_data; | ||||||
|     INSERT_PADDING_BYTES(0x2); |  | ||||||
|     u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
 |  | ||||||
|     AmiiboName amiibo_name; |     AmiiboName amiibo_name; | ||||||
|     INSERT_PADDING_BYTES(0x2); // Zero string terminator
 |     INSERT_PADDING_BYTES(0x2); // Zero string terminator
 | ||||||
|     u8 flags; |     u8 flags; | ||||||
|  | @ -430,9 +424,7 @@ struct RegisterInfo { | ||||||
| static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size"); | static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size"); | ||||||
| 
 | 
 | ||||||
| struct RegisterInfoPrivate { | struct RegisterInfoPrivate { | ||||||
|     HLE::Applets::MiiData mii_data; |     Mii::ChecksummedMiiData mii_data; | ||||||
|     INSERT_PADDING_BYTES(0x2); |  | ||||||
|     u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
 |  | ||||||
|     AmiiboName amiibo_name; |     AmiiboName amiibo_name; | ||||||
|     INSERT_PADDING_BYTES(0x2); // Zero string terminator
 |     INSERT_PADDING_BYTES(0x2); // Zero string terminator
 | ||||||
|     u8 flags; |     u8 flags; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue