GCMemcard: Split off HeaderData from Header to have a compact block of data for consistent initialization.

This commit is contained in:
Admiral H. Curtiss 2020-06-16 00:33:25 +02:00
parent cc52558c0e
commit e810d492f2
3 changed files with 49 additions and 18 deletions

View File

@ -304,7 +304,7 @@ void GCMemcard::UpdateBat(const BlockAlloc& bat)
bool GCMemcard::IsShiftJIS() const bool GCMemcard::IsShiftJIS() const
{ {
return m_header_block.m_encoding != 0; return m_header_block.m_data.m_encoding != 0;
} }
bool GCMemcard::Save() bool GCMemcard::Save()
@ -1549,32 +1549,48 @@ Header::Header()
std::memset(this, 0xFF, BLOCK_SIZE); std::memset(this, 0xFF, BLOCK_SIZE);
} }
Header::Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, void InitializeHeaderData(HeaderData* data, const CardFlashId& flash_id, u16 size_mbits,
u32 sram_language, u64 format_time) bool shift_jis, u32 rtc_bias, u32 sram_language, u64 format_time)
{ {
// Nintendo format algorithm. // Nintendo format algorithm.
// Constants are fixed by the GC SDK // Constants are fixed by the GC SDK
// Changing the constants will break memory card support // Changing the constants will break memory card support
static_assert(std::is_trivially_copyable_v<Header>); data->m_size_mb = size_mbits;
std::memset(this, 0xFF, BLOCK_SIZE); data->m_encoding = shift_jis ? 1 : 0;
m_size_mb = size_mbits; data->m_format_time = format_time;
m_encoding = shift_jis ? 1 : 0;
m_format_time = format_time;
u64 rand = format_time; u64 rand = format_time;
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); 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 = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
rand &= (u64)0x0000000000007fffULL; rand &= (u64)0x0000000000007fffULL;
} }
m_sram_bias = rtc_bias; data->m_sram_bias = rtc_bias;
m_sram_language = sram_language; data->m_sram_language = sram_language;
// TODO: determine the purpose of m_unknown_2 // TODO: determine the purpose of m_unknown_2
// 1 works for slot A, 0 works for both slot A and slot B // 1 works for slot A, 0 works for both slot A and slot B
memset(m_unknown_2.data(), 0, std::memset(
m_unknown_2.size()); // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; data->m_unknown_2.data(), 0,
m_device_id = 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<Header>);
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<Header>);
std::memset(this, 0xFF, BLOCK_SIZE);
m_data = data;
FixChecksums(); FixChecksums();
} }
@ -1622,7 +1638,7 @@ std::pair<u16, u16> Header::CalculateChecksums() const
std::array<u8, sizeof(Header)> raw; std::array<u8, sizeof(Header)> raw;
memcpy(raw.data(), this, raw.size()); 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_end = offsetof(Header, m_checksum);
constexpr size_t checksum_area_size = checksum_area_end - checksum_area_start; constexpr size_t checksum_area_size = checksum_area_end - checksum_area_start;
return CalculateMemcardChecksums(&raw[checksum_area_start], checksum_area_size); return CalculateMemcardChecksums(&raw[checksum_area_start], checksum_area_size);
@ -1633,7 +1649,7 @@ GCMemcardErrorCode Header::CheckForErrors(u16 card_size_mbits) const
GCMemcardErrorCode error_code; GCMemcardErrorCode error_code;
// total card size should match card size in header // 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); error_code.Set(GCMemcardValidityIssues::MISMATCHED_CARD_SIZE);
// unused areas, should always be filled with 0xFF // unused areas, should always be filled with 0xFF

View File

@ -170,7 +170,9 @@ static_assert(sizeof(GCMBlock) == BLOCK_SIZE);
static_assert(std::is_trivially_copyable_v<GCMBlock>); static_assert(std::is_trivially_copyable_v<GCMBlock>);
#pragma pack(push, 1) #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, // NOTE: libogc refers to 'Serial' as the first 0x20 bytes of the header,
// so the data from m_serial until m_unknown_2 (inclusive) // 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) // 2 bytes at 0x0024: Encoding (Windows-1252 or Shift JIS)
Common::BigEndianValue<u16> m_encoding; Common::BigEndianValue<u16> m_encoding;
};
static_assert(std::is_trivially_copyable_v<HeaderData>);
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) // 468 bytes at 0x0026: Unused (0xff)
std::array<u8, 468> m_unused_1; std::array<u8, 468> m_unused_1;
@ -222,6 +233,9 @@ struct Header
explicit Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, explicit Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias,
u32 sram_language, u64 format_time); 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. // Calculates the card serial numbers used for encrypting some save files.
std::pair<u32, u32> CalculateSerial() const; std::pair<u32, u32> CalculateSerial() const;

View File

@ -201,7 +201,8 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u
} }
// leave about 10% of free space on the card if possible // 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; const int reserved_blocks = total_blocks / 10;
// load files for other games // load files for other games