diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp index cfa0d5ad47..ee71f549aa 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp @@ -304,7 +304,7 @@ void GCMemcard::UpdateBat(const BlockAlloc& bat) bool GCMemcard::IsShiftJIS() const { - return m_header_block.m_encoding != 0; + return m_header_block.m_data.m_encoding != 0; } bool GCMemcard::Save() @@ -1549,32 +1549,48 @@ Header::Header() std::memset(this, 0xFF, BLOCK_SIZE); } -Header::Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, - u32 sram_language, u64 format_time) +void InitializeHeaderData(HeaderData* data, const CardFlashId& flash_id, u16 size_mbits, + bool shift_jis, u32 rtc_bias, u32 sram_language, u64 format_time) { // Nintendo format algorithm. // Constants are fixed by the GC SDK // Changing the constants will break memory card support - static_assert(std::is_trivially_copyable_v
); - std::memset(this, 0xFF, BLOCK_SIZE); - m_size_mb = size_mbits; - m_encoding = shift_jis ? 1 : 0; - m_format_time = format_time; + data->m_size_mb = size_mbits; + data->m_encoding = shift_jis ? 1 : 0; + data->m_format_time = format_time; u64 rand = format_time; for (int i = 0; i < 12; i++) { rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - m_serial[i] = (u8)(flash_id[i] + (u32)rand); + data->m_serial[i] = (u8)(flash_id[i] + (u32)rand); rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand &= (u64)0x0000000000007fffULL; } - m_sram_bias = rtc_bias; - m_sram_language = sram_language; + data->m_sram_bias = rtc_bias; + data->m_sram_language = sram_language; // TODO: determine the purpose of m_unknown_2 // 1 works for slot A, 0 works for both slot A and slot B - memset(m_unknown_2.data(), 0, - m_unknown_2.size()); // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; - m_device_id = 0; + std::memset( + data->m_unknown_2.data(), 0, + data->m_unknown_2.size()); // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; + data->m_device_id = 0; +} + +Header::Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time) +{ + static_assert(std::is_trivially_copyable_v
); + std::memset(this, 0xFF, BLOCK_SIZE); + InitializeHeaderData(&m_data, flash_id, size_mbits, shift_jis, rtc_bias, sram_language, + format_time); + FixChecksums(); +} + +Header::Header(const HeaderData& data) +{ + static_assert(std::is_trivially_copyable_v
); + std::memset(this, 0xFF, BLOCK_SIZE); + m_data = data; FixChecksums(); } @@ -1622,7 +1638,7 @@ std::pair Header::CalculateChecksums() const std::array raw; memcpy(raw.data(), this, raw.size()); - constexpr size_t checksum_area_start = offsetof(Header, m_serial); + constexpr size_t checksum_area_start = offsetof(Header, m_data); constexpr size_t checksum_area_end = offsetof(Header, m_checksum); constexpr size_t checksum_area_size = checksum_area_end - checksum_area_start; return CalculateMemcardChecksums(&raw[checksum_area_start], checksum_area_size); @@ -1633,7 +1649,7 @@ GCMemcardErrorCode Header::CheckForErrors(u16 card_size_mbits) const GCMemcardErrorCode error_code; // total card size should match card size in header - if (m_size_mb != card_size_mbits) + if (m_data.m_size_mb != card_size_mbits) error_code.Set(GCMemcardValidityIssues::MISMATCHED_CARD_SIZE); // unused areas, should always be filled with 0xFF diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.h b/Source/Core/Core/HW/GCMemcard/GCMemcard.h index 7d3ca6404a..8e86e69944 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.h @@ -170,7 +170,9 @@ static_assert(sizeof(GCMBlock) == BLOCK_SIZE); static_assert(std::is_trivially_copyable_v); #pragma pack(push, 1) -struct Header +// split off from Header to have a small struct with all the data needed to regenerate the header +// for GCI folders +struct HeaderData { // NOTE: libogc refers to 'Serial' as the first 0x20 bytes of the header, // so the data from m_serial until m_unknown_2 (inclusive) @@ -198,6 +200,15 @@ struct Header // 2 bytes at 0x0024: Encoding (Windows-1252 or Shift JIS) Common::BigEndianValue m_encoding; +}; +static_assert(std::is_trivially_copyable_v); + +void InitializeHeaderData(HeaderData* data, const CardFlashId& flash_id, u16 size_mbits, + bool shift_jis, u32 rtc_bias, u32 sram_language, u64 format_time); + +struct Header +{ + HeaderData m_data; // 468 bytes at 0x0026: Unused (0xff) std::array m_unused_1; @@ -222,6 +233,9 @@ struct Header explicit Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, u32 sram_language, u64 format_time); + // initialize a header block from existing HeaderData + explicit Header(const HeaderData& data); + // Calculates the card serial numbers used for encrypting some save files. std::pair CalculateSerial() const; diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp index 398e5b031c..9fe0c0dccb 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp @@ -201,7 +201,8 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u } // leave about 10% of free space on the card if possible - const int total_blocks = m_hdr.m_size_mb * Memcard::MBIT_TO_BLOCKS - Memcard::MC_FST_BLOCKS; + const int total_blocks = + m_hdr.m_data.m_size_mb * Memcard::MBIT_TO_BLOCKS - Memcard::MC_FST_BLOCKS; const int reserved_blocks = total_blocks / 10; // load files for other games