From fa0c99c987b4225926d01199f94b69cb058b01b2 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 28 Jul 2023 00:13:58 +0200 Subject: [PATCH 1/5] Move mii to own namespace and add checksummed mii data --- src/citra_qt/applets/mii_selector.cpp | 6 +- src/citra_qt/applets/mii_selector.h | 2 +- src/core/CMakeLists.txt | 2 + src/core/frontend/applets/mii_selector.cpp | 10 +- src/core/frontend/applets/mii_selector.h | 6 +- src/core/hle/applets/mii_selector.cpp | 47 ++-- src/core/hle/applets/mii_selector.h | 57 +--- src/core/hle/mii.cpp | 9 + src/core/hle/mii.h | 292 +++++++++++++++++++++ src/core/hle/service/nfc/amiibo_crypto.cpp | 4 - src/core/hle/service/nfc/nfc_device.cpp | 16 +- src/core/hle/service/nfc/nfc_types.h | 43 ++- 12 files changed, 359 insertions(+), 135 deletions(-) create mode 100644 src/core/hle/mii.cpp create mode 100644 src/core/hle/mii.h diff --git a/src/citra_qt/applets/mii_selector.cpp b/src/citra_qt/applets/mii_selector.cpp index 2099e675e6..f0bcbbae54 100644 --- a/src/citra_qt/applets/mii_selector.cpp +++ b/src/citra_qt/applets/mii_selector.cpp @@ -27,7 +27,8 @@ QtMiiSelectorDialog::QtMiiSelectorDialog(QWidget* parent, QtMiiSelector* mii_sel ? tr("Mii Selector") : QString::fromStdString(config.title)); - miis.push_back(HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); + miis.push_back( + HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData()); combobox->addItem(tr("Standard Mii")); for (const auto& mii : Frontend::LoadMiis()) { miis.push_back(mii); @@ -67,6 +68,5 @@ void QtMiiSelector::OpenDialog() { dialog.return_code, index); const auto mii_data = dialog.miis.at(index); - Finalize(dialog.return_code, - dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{}); + Finalize(dialog.return_code, dialog.return_code == 0 ? std::move(mii_data) : Mii::MiiData{}); } diff --git a/src/citra_qt/applets/mii_selector.h b/src/citra_qt/applets/mii_selector.h index c345493443..6b88674660 100644 --- a/src/citra_qt/applets/mii_selector.h +++ b/src/citra_qt/applets/mii_selector.h @@ -24,7 +24,7 @@ private: QVBoxLayout* layout; QtMiiSelector* mii_selector; u32 return_code = 0; - std::vector miis; + std::vector miis; friend class QtMiiSelector; }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 186f50fe3c..ae71ccc37b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -184,6 +184,8 @@ add_library(citra_core STATIC hle/kernel/wait_object.h hle/lock.cpp hle/lock.h + hle/mii.h + hle/mii.cpp hle/result.h hle/romfs.cpp hle/romfs.h diff --git a/src/core/frontend/applets/mii_selector.cpp b/src/core/frontend/applets/mii_selector.cpp index 6325e7a044..fcbc18213b 100644 --- a/src/core/frontend/applets/mii_selector.cpp +++ b/src/core/frontend/applets/mii_selector.cpp @@ -11,12 +11,12 @@ 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}; } -std::vector LoadMiis() { - std::vector miis; +std::vector LoadMiis() { + std::vector miis; std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)}; FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); @@ -36,7 +36,7 @@ std::vector LoadMiis() { u32 saved_miis_offset = 0x8; // The Mii Maker has a 100 Mii limit on the 3ds for (int i = 0; i < 100; ++i) { - HLE::Applets::MiiData mii; + Mii::MiiData mii; std::array mii_raw; file->Read(saved_miis_offset, sizeof(mii), mii_raw.data()); std::memcpy(&mii, mii_raw.data(), sizeof(mii)); @@ -53,7 +53,7 @@ std::vector LoadMiis() { void DefaultMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { MiiSelector::Setup(config); - Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); + Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData()); } } // namespace Frontend diff --git a/src/core/frontend/applets/mii_selector.h b/src/core/frontend/applets/mii_selector.h index 0cb0950559..7dc404d371 100644 --- a/src/core/frontend/applets/mii_selector.h +++ b/src/core/frontend/applets/mii_selector.h @@ -25,7 +25,7 @@ struct MiiSelectorConfig { struct MiiSelectorData { u32 return_code; - HLE::Applets::MiiData mii; + Mii::MiiData mii; }; class MiiSelector { @@ -43,14 +43,14 @@ public: * Stores the data so that the HLE applet in core can * send this to the calling application */ - void Finalize(u32 return_code, HLE::Applets::MiiData mii); + void Finalize(u32 return_code, Mii::MiiData mii); protected: MiiSelectorConfig config; MiiSelectorData data; }; -std::vector LoadMiis(); +std::vector LoadMiis(); class DefaultMiiSelector final : public MiiSelector { public: diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index f4ff0b408f..573f9d0526 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -71,9 +71,6 @@ void MiiSelector::Update() { const MiiSelectorData& data = frontend_applet->ReceiveData(); result.return_code = data.return_code; 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; // 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 // 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 - MiiData mii_data; - mii_data.mii_id = 0x03001030; + Mii::MiiData mii_data; + 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.specialness_and_creation_date = 0x98391EE4; - mii_data.creator_mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10}; - mii_data.padding = 0x0; - mii_data.mii_information = 0xA600; + mii_data.mii_id = 0x98391EE4; + mii_data.mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10}; + mii_data.pad = 0x0000; + mii_data.mii_details.raw = 0xA600; mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0}; - mii_data.width_height = 0x4040; - mii_data.appearance_bits1.raw = 0x0; - mii_data.appearance_bits2.raw = 0x0; + mii_data.height = 0x40; + mii_data.width = 0x40; + mii_data.face_style.raw = 0x00; + mii_data.face_details.raw = 0x00; mii_data.hair_style = 0x21; - mii_data.appearance_bits3.hair_color.Assign(0x1); - mii_data.appearance_bits3.flip_hair.Assign(0x0); - mii_data.unknown1 = 0x02684418; - mii_data.appearance_bits4.eyebrow_style.Assign(0x6); - mii_data.appearance_bits4.eyebrow_color.Assign(0x1); - mii_data.appearance_bits5.eyebrow_scale.Assign(0x4); - mii_data.appearance_bits5.eyebrow_yscale.Assign(0x3); - mii_data.appearance_bits6 = 0x4614; - mii_data.unknown2 = 0x81121768; - mii_data.allow_copying = 0x0D; - mii_data.unknown3 = {0x0, 0x0, 0x29, 0x0, 0x52, 0x48, 0x50}; + mii_data.hair_details.raw = 0x01; + mii_data.eye_details.raw = 0x02684418; + mii_data.eyebrow_details.raw = 0x26344614; + mii_data.nose_details.raw = 0x8112; + mii_data.mouth_details.raw = 0x1768; + mii_data.mustache_details.raw = 0x0D00; + mii_data.beard_details.raw = 0x0029; + mii_data.glasses_details.raw = 0x0052; + mii_data.mole_details.raw = 0x4850; mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0}; MiiResult result; @@ -122,8 +121,6 @@ MiiResult MiiSelector::GetStandardMiiResult() { result.is_guest_mii_selected = 0x0; result.selected_guest_mii_index = 0xFFFFFFFF; result.selected_mii_data = mii_data; - result.unknown1 = 0x0; - result.mii_data_checksum = 0x056C; result.guest_mii_name.fill(0x0); return result; diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index 50cf1bf4a9..63d7298de5 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "core/hle/applets/applet.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/mii.h" #include "core/hle/result.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); #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 creator_mac; - u16_be padding; - u16_be mii_information; - std::array 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 unknown3; - std::array author_name; -}; -static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); -#pragma pack(pop) - struct MiiResult { u32_be return_code; u32_be is_guest_mii_selected; u32_be selected_guest_mii_index; - MiiData selected_mii_data; - u16_be unknown1; - u16_be mii_data_checksum; + Mii::ChecksummedMiiData selected_mii_data; std::array guest_mii_name; }; static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); diff --git a/src/core/hle/mii.cpp b/src/core/hle/mii.cpp new file mode 100644 index 0000000000..be7ff183e4 --- /dev/null +++ b/src/core/hle/mii.cpp @@ -0,0 +1,9 @@ +#include +#include "core/hle/mii.h" + +namespace Mii { +u16 ChecksummedMiiData::CalcChecksum() { + // 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 \ No newline at end of file diff --git a/src/core/hle/mii.h b/src/core/hle/mii.h new file mode 100644 index 0000000000..ff1dcadb84 --- /dev/null +++ b/src/core/hle/mii.h @@ -0,0 +1,292 @@ +#pragma once + +#include +#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 +class MiiData { +public: + 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 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 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> yscale; + BitField<16, 5, u32> rotation; + BitField<21, 4, u32> xspacing; + BitField<25, 5, u32> yposition; + } 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> yscale; + BitField<15, 1, u32> pad; + BitField<16, 5, u32> rotation; + BitField<21, 4, u32> xspacing; + BitField<25, 5, u32> yposition; + } eyebrow_details{}; + + /// Nose details + union { + u16_be raw; + + BitField<0, 5, u16> style; + BitField<5, 4, u16> scale; + BitField<9, 5, u16> yposition; + } 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> yscale; + } 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> ypos; + } 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> ypos; + } glasses_details{}; + + /// Mole details + union { + u16_be raw; + + BitField<0, 1, u16> enable; + BitField<1, 5, u16> scale; + BitField<6, 5, u16> xpos; + BitField<11, 5, u16> ypos; + } mole_details{}; + + std::array author_name{}; ///< Name of Mii's author (Encoded using UTF16) +private: + template + void serialize(Archive& ar, const unsigned int) { + ar& magic; + ar& mii_options.raw; + ar& mii_pos.raw; + ar& console_identity.raw; + u64 system_id_ = system_id; + ar& system_id_; + system_id = system_id_; + u32 mii_id_ = mii_id; + ar& mii_id_; + mii_id = mii_id_; + ar& mac; + ar& pad; + u16 mii_details_ = mii_details.raw; + ar& mii_details_; + mii_details.raw = mii_details_; + ar& mii_name; + ar& height; + ar& width; + ar& face_style.raw; + ar& face_details.raw; + ar& hair_style; + ar& hair_details.raw; + u32 eye_details_ = eye_details.raw; + ar& eye_details_; + eye_details.raw = eye_details_; + u32 eyebrow_details_ = eyebrow_details.raw; + ar& eyebrow_details_; + eyebrow_details.raw = eyebrow_details_; + u16 nose_details_ = nose_details.raw; + ar& nose_details_; + nose_details.raw = nose_details_; + u16 mouth_details_ = mouth_details.raw; + ar& mouth_details_; + mouth_details.raw = mouth_details_; + u16 mustache_details_ = mustache_details.raw; + ar& mustache_details_; + mustache_details.raw = mustache_details_; + u16 beard_details_ = beard_details.raw; + ar& beard_details_; + beard_details.raw = beard_details_; + u16 glasses_details_ = glasses_details.raw; + ar& glasses_details_; + glasses_details.raw = glasses_details_; + u16 mole_details_ = mole_details.raw; + ar& mole_details_; + mole_details.raw = mole_details_; + ar& author_name; + } + friend class boost::serialization::access; +}; + +static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); + +class ChecksummedMiiData { +public: + ChecksummedMiiData() { + FixChecksum(); + } + ChecksummedMiiData(const ChecksummedMiiData& data) = default; + ChecksummedMiiData(ChecksummedMiiData&& data) = default; + ChecksummedMiiData& operator=(const ChecksummedMiiData&) = default; + ChecksummedMiiData& operator=(ChecksummedMiiData&&) = default; + + ChecksummedMiiData(const MiiData& data) : mii_data(data) { + FixChecksum(); + } + + ChecksummedMiiData(MiiData&& data) : mii_data(data) { + FixChecksum(); + } + + ChecksummedMiiData& operator=(const MiiData& data) { + mii_data = data; + FixChecksum(); + return *this; + } + + ChecksummedMiiData& operator=(MiiData&& data) { + mii_data = std::move(data); + FixChecksum(); + return *this; + } + + MiiData& GetMiiData() { + return mii_data; + } + + bool IsChecksumValid() { + return crc16 == CalcChecksum(); + } + + u16 CalcChecksum(); + + void FixChecksum() { + crc16 = CalcChecksum(); + } + +private: + MiiData mii_data{}; + INSERT_PADDING_BYTES(0x2); + u16_be crc16; + + template + void serialize(Archive& ar, const unsigned int) { + ar& mii_data; + u16 crc16_ = crc16; + ar& crc16_; + crc16 = crc16_; + } + friend class boost::serialization::access; +}; +#pragma pack(pop) +static_assert(sizeof(ChecksummedMiiData) == 0x60, + "ChecksummedMiiData structure has incorrect size"); +} // namespace Mii \ No newline at end of file diff --git a/src/core/hle/service/nfc/amiibo_crypto.cpp b/src/core/hle/service/nfc/amiibo_crypto.cpp index dc90f08552..a46da923b0 100644 --- a/src/core/hle/service/nfc/amiibo_crypto.cpp +++ b/src/core/hle/service/nfc/amiibo_crypto.cpp @@ -86,8 +86,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version; encoded_data.settings = nfc_data.user_memory.settings; 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_write_counter = nfc_data.user_memory.application_write_counter; 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.settings = encoded_data.settings; 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_write_counter = encoded_data.application_write_counter; nfc_data.user_memory.application_area_id = encoded_data.application_area_id; diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index a48859ebd6..5fb98cfcc3 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -538,7 +538,6 @@ ResultCode NfcDevice::GetRegisterInfo(RegisterInfo& register_info) const { // TODO: Validate this data register_info = { .mii_data = tag.file.owner_mii, - .owner_mii_aes_ccm = tag.file.owner_mii_aes_ccm, .amiibo_name = settings.amiibo_name, .flags = static_cast(settings.settings.raw & 0xf), .font_region = settings.country_code_id, @@ -627,8 +626,7 @@ ResultCode NfcDevice::DeleteRegisterInfo() { } CryptoPP::AutoSeededRandomPool rng; - const std::size_t mii_data_size = - sizeof(tag.file.owner_mii) + sizeof(tag.file.padding) + sizeof(tag.file.owner_mii_aes_ccm); + const std::size_t mii_data_size = sizeof(tag.file.owner_mii); std::array buffer{}; rng.GenerateBlock(buffer.data(), mii_data_size); @@ -663,12 +661,9 @@ ResultCode NfcDevice::SetRegisterInfoPrivate(const RegisterInfoPrivate& register 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; tag.file.owner_mii = register_info.mii_data; + tag.file.owner_mii.FixChecksum(); tag.file.mii_extension = {}; tag.file.unknown = 0; tag.file.unknown2 = {}; @@ -1060,9 +1055,7 @@ void NfcDevice::UpdateSettingsCrc() { void NfcDevice::UpdateRegisterInfoCrc() { #pragma pack(push, 1) struct CrcData { - HLE::Applets::MiiData mii; - INSERT_PADDING_BYTES(0x2); - u16 mii_crc; + Mii::ChecksummedMiiData mii; u8 application_id_byte; u8 unknown; u64 mii_extension; @@ -1073,7 +1066,6 @@ void NfcDevice::UpdateRegisterInfoCrc() { const CrcData crc_data{ .mii = tag.file.owner_mii, - .mii_crc = tag.file.owner_mii_aes_ccm, .application_id_byte = tag.file.application_id_byte, .unknown = tag.file.unknown, .mii_extension = tag.file.mii_extension, @@ -1101,8 +1093,6 @@ void NfcDevice::BuildAmiiboWithoutKeys() { settings.settings.font_region.Assign(0); settings.init_date = GetAmiiboDate(); 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 settings.settings.amiibo_initialized.Assign(1); diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h index 2a31a16dc4..08e5299854 100644 --- a/src/core/hle/service/nfc/nfc_types.h +++ b/src/core/hle/service/nfc/nfc_types.h @@ -269,20 +269,18 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz #pragma pack(1) struct EncryptedAmiiboFile { - u8 constant_value; // Must be A5 - u16_be write_counter; // Number of times the amiibo has been written? - u8 amiibo_version; // Amiibo file version - AmiiboSettings settings; // Encrypted amiibo settings - HashData hmac_tag; // Hash - AmiiboModelInfo model_info; // Encrypted amiibo model info - HashData keygen_salt; // Salt - HashData hmac_data; // Hash - HLE::Applets::MiiData owner_mii; // Encrypted Mii data - u16 padding; // Mii Padding - u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC - u64_be application_id; // Encrypted Game id - u16_be application_write_counter; // Encrypted Counter - u32_be application_area_id; // Encrypted Game id + u8 constant_value; // Must be A5 + u16_be write_counter; // Number of times the amiibo has been written? + u8 amiibo_version; // Amiibo file version + AmiiboSettings settings; // Encrypted amiibo settings + HashData hmac_tag; // Hash + AmiiboModelInfo model_info; // Encrypted amiibo model info + HashData keygen_salt; // Salt + HashData hmac_data; // Hash + Mii::ChecksummedMiiData owner_mii; // Encrypted Mii data + u64_be application_id; // Encrypted Game id + u16_be application_write_counter; // Encrypted Counter + u32_be application_area_id; // Encrypted Game id u8 application_id_byte; u8 unknown; u64 mii_extension; @@ -301,11 +299,9 @@ struct NTAG215File { u16_be write_counter; // Number of times the amiibo has been written? u8 amiibo_version; // Amiibo file version AmiiboSettings settings; - HLE::Applets::MiiData owner_mii; // Mii data - u16 padding; // Mii Padding - u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC - u64_be application_id; // Game id - u16_be application_write_counter; // Counter + Mii::ChecksummedMiiData owner_mii; // Mii data + u64_be application_id; // Game id + u16_be application_write_counter; // Counter u32_be application_area_id; u8 application_id_byte; u8 unknown; @@ -417,9 +413,7 @@ struct ModelInfo { static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size"); struct RegisterInfo { - HLE::Applets::MiiData mii_data; - INSERT_PADDING_BYTES(0x2); - u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC + Mii::ChecksummedMiiData mii_data; AmiiboName amiibo_name; INSERT_PADDING_BYTES(0x2); // Zero string terminator u8 flags; @@ -430,9 +424,7 @@ struct RegisterInfo { static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size"); struct RegisterInfoPrivate { - HLE::Applets::MiiData mii_data; - INSERT_PADDING_BYTES(0x2); - u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC + Mii::ChecksummedMiiData mii_data; AmiiboName amiibo_name; INSERT_PADDING_BYTES(0x2); // Zero string terminator u8 flags; @@ -441,7 +433,6 @@ struct RegisterInfoPrivate { INSERT_PADDING_BYTES(0x28); }; static_assert(sizeof(RegisterInfoPrivate) == 0xA4, "RegisterInfoPrivate is an invalid size"); -static_assert(std::is_trivial_v, "RegisterInfoPrivate must be trivial."); static_assert(std::is_trivially_copyable_v, "RegisterInfoPrivate must be trivially copyable."); From 7143b0652aaad0d5da4fc371142ddc3b257737ee Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 28 Jul 2023 12:52:00 +0200 Subject: [PATCH 2/5] Fix compile issues --- src/core/hle/mii.h | 62 +++++----------------------------------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/src/core/hle/mii.h b/src/core/hle/mii.h index ff1dcadb84..c10db0efab 100644 --- a/src/core/hle/mii.h +++ b/src/core/hle/mii.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "common/bit_field.h" #include "common/common_types.h" @@ -175,53 +176,7 @@ public: private: template void serialize(Archive& ar, const unsigned int) { - ar& magic; - ar& mii_options.raw; - ar& mii_pos.raw; - ar& console_identity.raw; - u64 system_id_ = system_id; - ar& system_id_; - system_id = system_id_; - u32 mii_id_ = mii_id; - ar& mii_id_; - mii_id = mii_id_; - ar& mac; - ar& pad; - u16 mii_details_ = mii_details.raw; - ar& mii_details_; - mii_details.raw = mii_details_; - ar& mii_name; - ar& height; - ar& width; - ar& face_style.raw; - ar& face_details.raw; - ar& hair_style; - ar& hair_details.raw; - u32 eye_details_ = eye_details.raw; - ar& eye_details_; - eye_details.raw = eye_details_; - u32 eyebrow_details_ = eyebrow_details.raw; - ar& eyebrow_details_; - eyebrow_details.raw = eyebrow_details_; - u16 nose_details_ = nose_details.raw; - ar& nose_details_; - nose_details.raw = nose_details_; - u16 mouth_details_ = mouth_details.raw; - ar& mouth_details_; - mouth_details.raw = mouth_details_; - u16 mustache_details_ = mustache_details.raw; - ar& mustache_details_; - mustache_details.raw = mustache_details_; - u16 beard_details_ = beard_details.raw; - ar& beard_details_; - beard_details.raw = beard_details_; - u16 glasses_details_ = glasses_details.raw; - ar& glasses_details_; - glasses_details.raw = glasses_details_; - u16 mole_details_ = mole_details.raw; - ar& mole_details_; - mole_details.raw = mole_details_; - ar& author_name; + ar& boost::serialization::make_binary_object(this, sizeof(MiiData)); } friend class boost::serialization::access; }; @@ -230,9 +185,7 @@ static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); class ChecksummedMiiData { public: - ChecksummedMiiData() { - FixChecksum(); - } + ChecksummedMiiData() = default; ChecksummedMiiData(const ChecksummedMiiData& data) = default; ChecksummedMiiData(ChecksummedMiiData&& data) = default; ChecksummedMiiData& operator=(const ChecksummedMiiData&) = default; @@ -274,15 +227,12 @@ public: private: MiiData mii_data{}; - INSERT_PADDING_BYTES(0x2); - u16_be crc16; + [[maybe_unused]] INSERT_PADDING_BYTES(0x2){}; + u16_be crc16{}; template void serialize(Archive& ar, const unsigned int) { - ar& mii_data; - u16 crc16_ = crc16; - ar& crc16_; - crc16 = crc16_; + ar& boost::serialization::make_binary_object(this, sizeof(ChecksummedMiiData)); } friend class boost::serialization::access; }; From bbd923d7a79a7ab44471fc23b98bab2a5bbdbfba Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 28 Jul 2023 13:36:55 +0200 Subject: [PATCH 3/5] Make mii classes trivial and add cast operator --- src/citra_qt/applets/mii_selector.cpp | 3 +- src/core/frontend/applets/mii_selector.cpp | 2 +- src/core/hle/mii.h | 77 ++++++++++------------ src/core/hle/service/nfc/nfc_types.h | 1 + 4 files changed, 37 insertions(+), 46 deletions(-) diff --git a/src/citra_qt/applets/mii_selector.cpp b/src/citra_qt/applets/mii_selector.cpp index f0bcbbae54..199b3f9247 100644 --- a/src/citra_qt/applets/mii_selector.cpp +++ b/src/citra_qt/applets/mii_selector.cpp @@ -27,8 +27,7 @@ QtMiiSelectorDialog::QtMiiSelectorDialog(QWidget* parent, QtMiiSelector* mii_sel ? tr("Mii Selector") : QString::fromStdString(config.title)); - miis.push_back( - HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData()); + miis.push_back(HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); combobox->addItem(tr("Standard Mii")); for (const auto& mii : Frontend::LoadMiis()) { miis.push_back(mii); diff --git a/src/core/frontend/applets/mii_selector.cpp b/src/core/frontend/applets/mii_selector.cpp index fcbc18213b..13a864f68d 100644 --- a/src/core/frontend/applets/mii_selector.cpp +++ b/src/core/frontend/applets/mii_selector.cpp @@ -53,7 +53,7 @@ std::vector LoadMiis() { void DefaultMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { MiiSelector::Setup(config); - Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData()); + Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); } } // namespace Frontend diff --git a/src/core/hle/mii.h b/src/core/hle/mii.h index c10db0efab..3e80c10df5 100644 --- a/src/core/hle/mii.h +++ b/src/core/hle/mii.h @@ -11,7 +11,7 @@ namespace Mii { // Reference: https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/mii.h class MiiData { public: - u8 magic{}; ///< Always 3? + u8 magic; ///< Always 3? /// Mii options union { @@ -21,7 +21,7 @@ public: 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_options; /// Mii position in Mii selector or Mii maker union { @@ -29,7 +29,7 @@ public: 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{}; + } mii_pos; /// Console Identity union { @@ -38,12 +38,12 @@ public: 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{}; + } 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 mac{}; ///< Creator's system's full MAC address - u16 pad{}; ///< Padding + u64_be system_id; ///< Identifies the system that the Mii was created on (Determines pants) + u32_be mii_id; ///< ID of Mii + std::array mac; ///< Creator's system's full MAC address + u16 pad; ///< Padding /// Mii details union { @@ -54,11 +54,11 @@ public: 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{}; + } mii_details; - std::array mii_name{}; ///< Name of Mii (Encoded using UTF16) - u8 height{}; ///< How tall the Mii is - u8 width{}; ///< How wide the Mii is + std::array 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 { @@ -67,7 +67,7 @@ public: 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_style; /// Face details union { @@ -75,9 +75,9 @@ public: BitField<0, 4, u8> wrinkles; BitField<4, 4, u8> makeup; - } face_details{}; + } face_details; - u8 hair_style{}; + u8 hair_style; /// Hair details union { @@ -85,7 +85,7 @@ public: BitField<0, 3, u8> color; BitField<3, 1, u8> flip; - } hair_details{}; + } hair_details; /// Eye details union { @@ -98,7 +98,7 @@ public: BitField<16, 5, u32> rotation; BitField<21, 4, u32> xspacing; BitField<25, 5, u32> yposition; - } eye_details{}; + } eye_details; /// Eyebrow details union { @@ -112,7 +112,7 @@ public: BitField<16, 5, u32> rotation; BitField<21, 4, u32> xspacing; BitField<25, 5, u32> yposition; - } eyebrow_details{}; + } eyebrow_details; /// Nose details union { @@ -121,7 +121,7 @@ public: BitField<0, 5, u16> style; BitField<5, 4, u16> scale; BitField<9, 5, u16> yposition; - } nose_details{}; + } nose_details; /// Mouth details union { @@ -131,7 +131,7 @@ public: BitField<6, 3, u16> color; BitField<9, 4, u16> scale; BitField<13, 3, u16> yscale; - } mouth_details{}; + } mouth_details; /// Mustache details union { @@ -140,7 +140,7 @@ public: BitField<0, 5, u16> mouth_yposition; BitField<5, 3, u16> mustach_style; BitField<8, 2, u16> pad; - } mustache_details{}; + } mustache_details; /// Beard details union { @@ -150,7 +150,7 @@ public: BitField<3, 3, u16> color; BitField<6, 4, u16> scale; BitField<10, 5, u16> ypos; - } beard_details{}; + } beard_details; /// Glasses details union { @@ -160,7 +160,7 @@ public: BitField<4, 3, u16> color; BitField<7, 4, u16> scale; BitField<11, 5, u16> ypos; - } glasses_details{}; + } glasses_details; /// Mole details union { @@ -170,9 +170,9 @@ public: BitField<1, 5, u16> scale; BitField<6, 5, u16> xpos; BitField<11, 5, u16> ypos; - } mole_details{}; + } mole_details; - std::array author_name{}; ///< Name of Mii's author (Encoded using UTF16) + std::array author_name; ///< Name of Mii's author (Encoded using UTF16) private: template void serialize(Archive& ar, const unsigned int) { @@ -182,23 +182,11 @@ private: }; static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); +static_assert(std::is_trivial_v, "MiiData must be trivial."); +static_assert(std::is_trivially_copyable_v, "MiiData must be trivially copyable."); class ChecksummedMiiData { public: - ChecksummedMiiData() = default; - ChecksummedMiiData(const ChecksummedMiiData& data) = default; - ChecksummedMiiData(ChecksummedMiiData&& data) = default; - ChecksummedMiiData& operator=(const ChecksummedMiiData&) = default; - ChecksummedMiiData& operator=(ChecksummedMiiData&&) = default; - - ChecksummedMiiData(const MiiData& data) : mii_data(data) { - FixChecksum(); - } - - ChecksummedMiiData(MiiData&& data) : mii_data(data) { - FixChecksum(); - } - ChecksummedMiiData& operator=(const MiiData& data) { mii_data = data; FixChecksum(); @@ -211,7 +199,7 @@ public: return *this; } - MiiData& GetMiiData() { + operator MiiData() const { return mii_data; } @@ -226,9 +214,9 @@ public: } private: - MiiData mii_data{}; - [[maybe_unused]] INSERT_PADDING_BYTES(0x2){}; - u16_be crc16{}; + MiiData mii_data; + [[maybe_unused]] INSERT_PADDING_BYTES(0x2); + u16_be crc16; template void serialize(Archive& ar, const unsigned int) { @@ -239,4 +227,7 @@ private: #pragma pack(pop) static_assert(sizeof(ChecksummedMiiData) == 0x60, "ChecksummedMiiData structure has incorrect size"); +static_assert(std::is_trivial_v, "ChecksummedMiiData must be trivial."); +static_assert(std::is_trivially_copyable_v, + "ChecksummedMiiData must be trivially copyable."); } // namespace Mii \ No newline at end of file diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h index 08e5299854..8b08aca9c1 100644 --- a/src/core/hle/service/nfc/nfc_types.h +++ b/src/core/hle/service/nfc/nfc_types.h @@ -433,6 +433,7 @@ struct RegisterInfoPrivate { INSERT_PADDING_BYTES(0x28); }; static_assert(sizeof(RegisterInfoPrivate) == 0xA4, "RegisterInfoPrivate is an invalid size"); +static_assert(std::is_trivial_v, "RegisterInfoPrivate must be trivial."); static_assert(std::is_trivially_copyable_v, "RegisterInfoPrivate must be trivially copyable."); From d89a8466e43be1de30a184daa7986bb7820ded3f Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 28 Jul 2023 15:34:44 +0200 Subject: [PATCH 4/5] Fix Android side --- src/android/app/src/main/jni/applets/mii_selector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/src/main/jni/applets/mii_selector.cpp b/src/android/app/src/main/jni/applets/mii_selector.cpp index 2009a84ec8..2bb48db9a0 100644 --- a/src/android/app/src/main/jni/applets/mii_selector.cpp +++ b/src/android/app/src/main/jni/applets/mii_selector.cpp @@ -53,7 +53,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { const u32 return_code = static_cast( env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J"))); if (return_code == 1) { - Finalize(return_code, HLE::Applets::MiiData{}); + Finalize(return_code, Mii::MiiData{}); return; } From 0f4480a232f7dcf22f29e2945a5c561ab0b7da91 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 28 Jul 2023 17:50:21 +0200 Subject: [PATCH 5/5] Add new line at the end of files. --- src/core/hle/mii.cpp | 2 +- src/core/hle/mii.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/mii.cpp b/src/core/hle/mii.cpp index be7ff183e4..ef8a5e6a39 100644 --- a/src/core/hle/mii.cpp +++ b/src/core/hle/mii.cpp @@ -6,4 +6,4 @@ u16 ChecksummedMiiData::CalcChecksum() { // 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 \ No newline at end of file +} // namespace Mii diff --git a/src/core/hle/mii.h b/src/core/hle/mii.h index 3e80c10df5..ae1da5e98a 100644 --- a/src/core/hle/mii.h +++ b/src/core/hle/mii.h @@ -230,4 +230,4 @@ static_assert(sizeof(ChecksummedMiiData) == 0x60, static_assert(std::is_trivial_v, "ChecksummedMiiData must be trivial."); static_assert(std::is_trivially_copyable_v, "ChecksummedMiiData must be trivially copyable."); -} // namespace Mii \ No newline at end of file +} // namespace Mii