EXI_Memcard: HLE memcard Formatting, GCMemcard: Add static format function, cleanup checksums code
This commit is contained in:
parent
86950e7cce
commit
8d91f1e0c1
|
@ -26,6 +26,7 @@
|
||||||
#include "EXI_Device.h"
|
#include "EXI_Device.h"
|
||||||
#include "EXI_DeviceMemoryCard.h"
|
#include "EXI_DeviceMemoryCard.h"
|
||||||
#include "Sram.h"
|
#include "Sram.h"
|
||||||
|
#include "../../DolphinWx/Src/MemoryCards/GCMemcard.h"
|
||||||
|
|
||||||
#define MC_STATUS_BUSY 0x80
|
#define MC_STATUS_BUSY 0x80
|
||||||
#define MC_STATUS_UNLOCKED 0x40
|
#define MC_STATUS_UNLOCKED 0x40
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
#define MC_STATUS_PROGRAMEERROR 0x08
|
#define MC_STATUS_PROGRAMEERROR 0x08
|
||||||
#define MC_STATUS_READY 0x01
|
#define MC_STATUS_READY 0x01
|
||||||
#define SIZE_TO_Mb (1024 * 8 * 16)
|
#define SIZE_TO_Mb (1024 * 8 * 16)
|
||||||
|
#define MC_HDR_SIZE 0xA000
|
||||||
|
|
||||||
static CEXIMemoryCard *cards[2];
|
static CEXIMemoryCard *cards[2];
|
||||||
|
|
||||||
|
@ -84,7 +86,6 @@ CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rF
|
||||||
|
|
||||||
INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
||||||
pFile.ReadBytes(memory_card_content, memory_card_size);
|
pFile.ReadBytes(memory_card_content, memory_card_size);
|
||||||
SetCardFlashID(memory_card_content, card_index);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -94,11 +95,11 @@ CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rF
|
||||||
memory_card_size = nintendo_card_id * SIZE_TO_Mb;
|
memory_card_size = nintendo_card_id * SIZE_TO_Mb;
|
||||||
|
|
||||||
memory_card_content = new u8[memory_card_size];
|
memory_card_content = new u8[memory_card_size];
|
||||||
memset(memory_card_content, 0xFF, memory_card_size);
|
GCMemcard::Format(memory_card_content, m_strFilename.find(".JAP.raw") != std::string::npos, nintendo_card_id);
|
||||||
|
memset(memory_card_content+MC_HDR_SIZE, 0xFF, memory_card_size-MC_HDR_SIZE);
|
||||||
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
|
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
|
||||||
Flush();
|
|
||||||
}
|
}
|
||||||
|
SetCardFlashID(memory_card_content, card_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void innerFlush(FlushData* data)
|
void innerFlush(FlushData* data)
|
||||||
|
|
|
@ -227,7 +227,7 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
|
||||||
|
|
||||||
bool GCMemcard::IsAsciiEncoding()
|
bool GCMemcard::IsAsciiEncoding()
|
||||||
{
|
{
|
||||||
return hdr.Encoding[1] == 0;
|
return hdr.Encoding == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCMemcard::Save()
|
bool GCMemcard::Save()
|
||||||
|
@ -245,51 +245,49 @@ bool GCMemcard::Save()
|
||||||
return mcdFile.Close();
|
return mcdFile.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
|
void GCMemcard::calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum)
|
||||||
{
|
{
|
||||||
*c1 = 0;*c2 = 0;
|
*csum = *inv_csum = 0;
|
||||||
for (u32 i = 0; i < num; ++i)
|
|
||||||
|
for (u32 i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
//weird warnings here
|
//weird warnings here
|
||||||
*c1 += Common::swap16(buf[i]);
|
*csum += BE16(buf[i]);
|
||||||
*c2 += Common::swap16((u16)(buf[i] ^ 0xffff));
|
*inv_csum += BE16((u16)(buf[i] ^ 0xffff));
|
||||||
}
|
}
|
||||||
if (*c1 == 0xffff)
|
*csum = BE16(*csum);
|
||||||
|
*inv_csum = BE16(*inv_csum);
|
||||||
|
if (*csum == 0xffff)
|
||||||
{
|
{
|
||||||
*c1 = 0;
|
*csum = 0;
|
||||||
}
|
}
|
||||||
if (*c2 == 0xffff)
|
if (*inv_csum == 0xffff)
|
||||||
{
|
{
|
||||||
*c2 = 0;
|
*inv_csum = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GCMemcard::TestChecksums()
|
u32 GCMemcard::TestChecksums()
|
||||||
{
|
{
|
||||||
u16 csum1=0,
|
u16 csum=0,
|
||||||
csum2=0;
|
csum_inv=0;
|
||||||
|
|
||||||
u32 results = 0;
|
u32 results = 0;
|
||||||
|
|
||||||
calc_checksumsBE((u16*)&hdr, 0xFE , &csum1, &csum2);
|
calc_checksumsBE((u16*)&hdr, 0xFE , &csum, &csum_inv);
|
||||||
if (BE16(hdr.CheckSum1) != csum1) results |= 1;
|
if ((hdr.Checksum != csum) || (hdr.Checksum_Inv != csum_inv)) results |= 1;
|
||||||
if (BE16(hdr.CheckSum2) != csum2) results |= 1;
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
|
calc_checksumsBE((u16*)&dir, 0xFFE, &csum, &csum_inv);
|
||||||
if (BE16(dir.CheckSum1) != csum1) results |= 2;
|
if ((dir.Checksum != csum) || (dir.Checksum_Inv != csum_inv)) results |= 2;
|
||||||
if (BE16(dir.CheckSum2) != csum2) results |= 2;
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
|
calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum, &csum_inv);
|
||||||
if (BE16(dir_backup.CheckSum1) != csum1) results |= 4;
|
if ((dir_backup.Checksum != csum) || (dir_backup.Checksum_Inv != csum_inv)) results |= 4;
|
||||||
if (BE16(dir_backup.CheckSum2) != csum2) results |= 4;
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2);
|
calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum, &csum_inv);
|
||||||
if (BE16(bat.CheckSum1) != csum1) results |= 8;
|
if ((bat.Checksum != csum) || (bat.Checksum_Inv != csum_inv)) results |= 8;
|
||||||
if (BE16(bat.CheckSum2) != csum2) results |= 8;
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2);
|
calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum, &csum_inv);
|
||||||
if (BE16(bat_backup.CheckSum1) != csum1) results |= 16;
|
if ((bat_backup.Checksum != csum) || (bat_backup.Checksum_Inv != csum_inv)) results |= 16;
|
||||||
if (BE16(bat_backup.CheckSum2) != csum2) results |= 16;
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
@ -299,38 +297,11 @@ bool GCMemcard::FixChecksums()
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u16 csum1=0,
|
calc_checksumsBE((u16*)&hdr, 0xFE, &hdr.Checksum, &hdr.Checksum_Inv);
|
||||||
csum2=0;
|
calc_checksumsBE((u16*)&dir, 0xFFE, &dir.Checksum, &dir.Checksum_Inv);
|
||||||
|
calc_checksumsBE((u16*)&dir_backup, 0xFFE, &dir_backup.Checksum, &dir_backup.Checksum_Inv);
|
||||||
calc_checksumsBE((u16*)&hdr, 0xFE, &csum1, &csum2);
|
calc_checksumsBE((u16*)&bat+2, 0xFFE, &bat.Checksum, &bat.Checksum_Inv);
|
||||||
hdr.CheckSum1[0] = u8(csum1 >> 8);
|
calc_checksumsBE((u16*)&bat_backup+2, 0xFFE, &bat_backup.Checksum, &bat_backup.Checksum_Inv);
|
||||||
hdr.CheckSum1[1] = u8(csum1);
|
|
||||||
hdr.CheckSum2[0] = u8(csum2 >> 8);
|
|
||||||
hdr.CheckSum2[1] = u8(csum2);
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
|
|
||||||
dir.CheckSum1[0] = u8(csum1 >> 8);
|
|
||||||
dir.CheckSum1[1] = u8(csum1);
|
|
||||||
dir.CheckSum2[0] = u8(csum2 >> 8);
|
|
||||||
dir.CheckSum2[1] = u8(csum2);
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
|
|
||||||
dir_backup.CheckSum1[0] = u8(csum1 >> 8);
|
|
||||||
dir_backup.CheckSum1[1] = u8(csum1);
|
|
||||||
dir_backup.CheckSum2[0] = u8(csum2 >> 8);
|
|
||||||
dir_backup.CheckSum2[1] = u8(csum2);
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2);
|
|
||||||
bat.CheckSum1[0] = u8(csum1 >> 8);
|
|
||||||
bat.CheckSum1[1] = u8(csum1);
|
|
||||||
bat.CheckSum2[0] = u8(csum2 >> 8);
|
|
||||||
bat.CheckSum2[1] = u8(csum2);
|
|
||||||
|
|
||||||
calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2);
|
|
||||||
bat_backup.CheckSum1[0] = u8(csum1 >> 8);
|
|
||||||
bat_backup.CheckSum1[1] = u8(csum1);
|
|
||||||
bat_backup.CheckSum2[0] = u8(csum2 >> 8);
|
|
||||||
bat_backup.CheckSum2[1] = u8(csum2);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -620,8 +591,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
dir.Dir[i] = direntry;
|
dir.Dir[i] = direntry;
|
||||||
dir.Dir[i].FirstBlock[0] = u8(firstFree1 >> 8);
|
*(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1);
|
||||||
dir.Dir[i].FirstBlock[1] = u8(firstFree1);
|
|
||||||
if (!remove)
|
if (!remove)
|
||||||
{
|
{
|
||||||
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1;
|
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1;
|
||||||
|
@ -642,7 +612,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||||
int j = 2;
|
int j = 2;
|
||||||
while(j < BE16(direntry.BlockCount) + 1)
|
while(j < BE16(direntry.BlockCount) + 1)
|
||||||
{
|
{
|
||||||
bat_backup.Map[i] = Common::swap16(last + (u16)j);
|
bat_backup.Map[i] = BE16(last + (u16)j);
|
||||||
i++;
|
i++;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
@ -654,25 +624,16 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||||
}
|
}
|
||||||
|
|
||||||
//update last allocated block
|
//update last allocated block
|
||||||
int lastallocated = BE16(bat_backup.LastAllocated) + j - 1;
|
*(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1);
|
||||||
bat_backup.LastAllocated[0] = u8(lastallocated >> 8);
|
|
||||||
bat_backup.LastAllocated[1] = u8(lastallocated);
|
|
||||||
|
|
||||||
//update freespace counter
|
//update freespace counter
|
||||||
int freespace1 = totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS;
|
*(u16*)&bat_backup.FreeBlocks = BE16(totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS);
|
||||||
bat_backup.FreeBlocks[0] = u8(freespace1 >> 8);
|
|
||||||
bat_backup.FreeBlocks[1] = u8(freespace1);
|
|
||||||
|
|
||||||
|
|
||||||
if (!remove)
|
if (!remove)
|
||||||
{ // ... and dir update counter
|
{ // ... and dir update counter
|
||||||
int updateCtr = BE16(dir_backup.UpdateCounter) + 1;
|
*(u16*)&dir_backup.UpdateCounter = BE16(BE16(dir_backup.UpdateCounter) + 1);
|
||||||
dir_backup.UpdateCounter[0] = u8(updateCtr >> 8);
|
|
||||||
dir_backup.UpdateCounter[1] = u8(updateCtr);
|
|
||||||
// ... and bat update counter
|
// ... and bat update counter
|
||||||
updateCtr = BE16(bat_backup.UpdateCounter) + 1;
|
*(u16*)&bat_backup.UpdateCounter = BE16(BE16(bat_backup.UpdateCounter) + 1);
|
||||||
bat_backup.UpdateCounter[0] = u8(updateCtr >> 8);
|
|
||||||
bat_backup.UpdateCounter[1] = u8(updateCtr);
|
|
||||||
}
|
}
|
||||||
bat = bat_backup;
|
bat = bat_backup;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
@ -698,9 +659,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||||
|
|
||||||
//free the blocks
|
//free the blocks
|
||||||
int blocks_left = BE16(dir.Dir[index].BlockCount);
|
int blocks_left = BE16(dir.Dir[index].BlockCount);
|
||||||
int block = BE16(dir.Dir[index].FirstBlock) - 1;
|
*(u16*)&bat.LastAllocated = BE16(BE16(dir.Dir[index].FirstBlock) - 1);
|
||||||
bat.LastAllocated[0] = (u8)(block >> 8);
|
|
||||||
bat.LastAllocated[1] = (u8)block;
|
|
||||||
|
|
||||||
u8 nextIndex = index + 1;
|
u8 nextIndex = index + 1;
|
||||||
memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE);
|
memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE);
|
||||||
|
@ -713,9 +672,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||||
//Only get file data if it is a valid dir entry
|
//Only get file data if it is a valid dir entry
|
||||||
if (BE16(tempDEntry->FirstBlock) != 0xFFFF)
|
if (BE16(tempDEntry->FirstBlock) != 0xFFFF)
|
||||||
{
|
{
|
||||||
u16 freeBlock= BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount);
|
*(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount));
|
||||||
bat.FreeBlocks[0] = u8(freeBlock >> 8);
|
|
||||||
bat.FreeBlocks[1] = u8(freeBlock);
|
|
||||||
|
|
||||||
u16 size = DEntry_BlockCount(nextIndex);
|
u16 size = DEntry_BlockCount(nextIndex);
|
||||||
if (size != 0xFFFF)
|
if (size != 0xFFFF)
|
||||||
|
@ -754,9 +711,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// increment update counter
|
// increment update counter
|
||||||
int updateCtr = BE16(dir.UpdateCounter) + 1;
|
*(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1);
|
||||||
dir.UpdateCounter[0] = u8(updateCtr >> 8);
|
|
||||||
dir.UpdateCounter[1] = u8(updateCtr);
|
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -989,9 +944,7 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length)
|
||||||
// It is stored only within the corresponding GSV file.
|
// It is stored only within the corresponding GSV file.
|
||||||
// If the GCS file is added without using the GameSaves software,
|
// If the GCS file is added without using the GameSaves software,
|
||||||
// the value stored is always "1"
|
// the value stored is always "1"
|
||||||
int blockCount = length / BLOCK_SIZE;
|
*(u16*)&tempDEntry->BlockCount = BE16(length / BLOCK_SIZE);
|
||||||
tempDEntry->BlockCount[0] = u8(blockCount >> 8);
|
|
||||||
tempDEntry->BlockCount[1] = u8(blockCount);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SAV:
|
case SAV:
|
||||||
|
@ -1157,69 +1110,55 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCMemcard::Format(bool sjis, int slot, u16 SizeMb)
|
|
||||||
|
bool GCMemcard::Format(u8 * card_data, bool sjis, u16 SizeMb)
|
||||||
{
|
{
|
||||||
// Currently only formats cards for slot A
|
if (!card_data)
|
||||||
m_sizeMb = SizeMb;
|
return false;
|
||||||
mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
|
memset(card_data, 0xFF, BLOCK_SIZE*3);
|
||||||
|
memset(card_data + BLOCK_SIZE*3, 0, BLOCK_SIZE*2);
|
||||||
|
|
||||||
SRAM m_SRAM;
|
GCMC_Header gcp;
|
||||||
|
gcp.hdr = (Header*)card_data;
|
||||||
|
gcp.dir = (Directory *)(card_data + BLOCK_SIZE);
|
||||||
|
gcp.dir_backup = (Directory *)(card_data + BLOCK_SIZE*2);
|
||||||
|
gcp.bat = (BlockAlloc *)(card_data + BLOCK_SIZE*3);
|
||||||
|
gcp.bat_backup = (BlockAlloc *)(card_data + BLOCK_SIZE*4);
|
||||||
|
|
||||||
|
*(u16*)gcp.hdr->SizeMb = BE16(SizeMb);
|
||||||
|
*(u16*)gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
|
||||||
|
|
||||||
|
FormatInternal(gcp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
File::IOFile pStream(File::GetUserPath(F_GCSRAM_IDX), "rb");
|
bool GCMemcard::Format(bool sjis, u16 SizeMb)
|
||||||
if (pStream)
|
{
|
||||||
{
|
|
||||||
pStream.ReadBytes(&m_SRAM, 64);
|
|
||||||
pStream.Close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_SRAM = sram_dump;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u64 time = CEXIIPL::GetGCTime();
|
|
||||||
u64 rand = Common::swap64(time);
|
|
||||||
|
|
||||||
memset(&hdr, 0xFF, BLOCK_SIZE);
|
memset(&hdr, 0xFF, BLOCK_SIZE);
|
||||||
for(int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
|
|
||||||
hdr.serial[i] = (u8)(m_SRAM.flash_id[slot][i] + (u32)rand);
|
|
||||||
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
|
|
||||||
rand &= (u64)0x0000000000007fffULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr.fmtTime.high = (time >> 32) & 0xFFFFFFFF;
|
|
||||||
hdr.fmtTime.low = time & 0xFFFFFFFF;
|
|
||||||
*(u32*)&(hdr.SramBias) = m_SRAM.counter_bias;
|
|
||||||
*(u32*)&(hdr.SramLang) = m_SRAM.lang;
|
|
||||||
// TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B
|
|
||||||
*(u32*)&(hdr.Unk2) = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000;
|
|
||||||
*(u16*)&(hdr.deviceID) = 0;
|
|
||||||
*(u16*)&(hdr.SizeMb) = Common::swap16(m_sizeMb);
|
|
||||||
*(u16*)&(hdr.Encoding) = Common::swap16(sjis ? 1 : 0);
|
|
||||||
|
|
||||||
memset(&dir, 0xFF, BLOCK_SIZE);
|
memset(&dir, 0xFF, BLOCK_SIZE);
|
||||||
memset(&dir_backup, 0xFF, BLOCK_SIZE);
|
memset(&dir_backup, 0xFF, BLOCK_SIZE);
|
||||||
*(u16*)&dir.UpdateCounter = 0;
|
|
||||||
*(u16*)&dir_backup.UpdateCounter = Common::swap16(1);
|
|
||||||
|
|
||||||
|
|
||||||
maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
|
|
||||||
|
|
||||||
memset(&bat, 0, BLOCK_SIZE);
|
memset(&bat, 0, BLOCK_SIZE);
|
||||||
memset(&bat_backup, 0, BLOCK_SIZE);
|
memset(&bat_backup, 0, BLOCK_SIZE);
|
||||||
*(u16*)&bat.UpdateCounter = 0;
|
|
||||||
*(u16*)&bat_backup.UpdateCounter = Common::swap16(1);
|
|
||||||
*(u16*)&bat.FreeBlocks = *(u16*)&bat_backup.FreeBlocks = Common::swap16(maxBlock - MC_FST_BLOCKS);
|
|
||||||
*(u16*)&bat.LastAllocated = *(u16*)&bat_backup.LastAllocated = Common::swap16(4);
|
|
||||||
|
|
||||||
|
GCMC_Header gcp;
|
||||||
|
gcp.hdr = &hdr;
|
||||||
|
gcp.dir = &dir;
|
||||||
|
gcp.dir_backup = &dir_backup;
|
||||||
|
gcp.bat = &bat;
|
||||||
|
gcp.bat_backup = &bat_backup;
|
||||||
|
|
||||||
|
*(u16*)hdr.SizeMb = BE16(SizeMb);
|
||||||
|
*(u16*)hdr.Encoding = BE16(sjis ? 1 : 0);
|
||||||
|
FormatInternal(gcp);
|
||||||
|
|
||||||
|
m_sizeMb = SizeMb;
|
||||||
|
maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
|
||||||
if (mc_data)
|
if (mc_data)
|
||||||
{
|
{
|
||||||
delete mc_data;
|
delete mc_data;
|
||||||
mc_data = NULL;
|
mc_data = NULL;
|
||||||
}
|
}
|
||||||
|
mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
|
||||||
mc_data = new u8[mc_data_size];
|
mc_data = new u8[mc_data_size];
|
||||||
if (!mc_data)
|
if (!mc_data)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1227,6 +1166,41 @@ bool GCMemcard::Format(bool sjis, int slot, u16 SizeMb)
|
||||||
memset(mc_data, 0xFF, mc_data_size);
|
memset(mc_data, 0xFF, mc_data_size);
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
|
|
||||||
FixChecksums();
|
|
||||||
return Save();
|
return Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCMemcard::FormatInternal(GCMC_Header &GCP)
|
||||||
|
{
|
||||||
|
Header *p_hdr = GCP.hdr;
|
||||||
|
u64 rand = CEXIIPL::GetGCTime();
|
||||||
|
p_hdr->formatTime = Common::swap64(rand);
|
||||||
|
|
||||||
|
for(int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
|
||||||
|
p_hdr->serial[i] = (u8)(g_SRAM.flash_id[0][i] + (u32)rand);
|
||||||
|
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
|
||||||
|
rand &= (u64)0x0000000000007fffULL;
|
||||||
|
}
|
||||||
|
*(u32*)&p_hdr->SramBias = g_SRAM.counter_bias;
|
||||||
|
*(u32*)&p_hdr->SramLang = g_SRAM.lang;
|
||||||
|
// TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B
|
||||||
|
*(u32*)&p_hdr->Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000;
|
||||||
|
*(u16*)&p_hdr->deviceID = 0;
|
||||||
|
calc_checksumsBE((u16*)p_hdr, 0xFE, &p_hdr->Checksum, &p_hdr->Checksum_Inv);
|
||||||
|
|
||||||
|
Directory *p_dir = GCP.dir,
|
||||||
|
*p_dir_backup = GCP.dir_backup;
|
||||||
|
*(u16*)&p_dir->UpdateCounter = 0;
|
||||||
|
*(u16*)&p_dir_backup->UpdateCounter = BE16(1);
|
||||||
|
calc_checksumsBE((u16*)p_dir, 0xFFE, &p_dir->Checksum, &p_dir->Checksum_Inv);
|
||||||
|
calc_checksumsBE((u16*)p_dir_backup, 0xFFE, &p_dir_backup->Checksum, &p_dir_backup->Checksum_Inv);
|
||||||
|
|
||||||
|
BlockAlloc *p_bat = GCP.bat,
|
||||||
|
*p_bat_backup = GCP.bat_backup;
|
||||||
|
*(u16*)&p_bat_backup->UpdateCounter = BE16(1);
|
||||||
|
*(u16*)&p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS);
|
||||||
|
*(u16*)&p_bat->LastAllocated = *(u16*)&p_bat_backup->LastAllocated = BE16(4);
|
||||||
|
calc_checksumsBE((u16*)p_bat+2, 0xFFE, &p_bat->Checksum, &p_bat->Checksum_Inv);
|
||||||
|
calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv);
|
||||||
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "../../../Core/Src/HW/EXI_DeviceIPL.h"
|
#include "../../../Core/Src/HW/EXI_DeviceIPL.h"
|
||||||
|
|
||||||
#define BE32(x) ((u32((x)[0])<<24) | (u32((x)[1])<<16) | (u32((x)[2])<<8) | u32((x)[3]))
|
#define BE32(x) (Common::swap32(x))
|
||||||
#define BE16(x) ((u16((x)[0])<<8) | u16((x)[1]))
|
#define BE16(x) (Common::swap16(x))
|
||||||
#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));
|
#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -81,15 +81,10 @@ private:
|
||||||
u16 m_sizeMb;
|
u16 m_sizeMb;
|
||||||
|
|
||||||
#pragma pack(push,1)
|
#pragma pack(push,1)
|
||||||
struct OSTime {
|
|
||||||
u32 low;
|
|
||||||
u32 high;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Header { //Offset Size Description
|
struct Header { //Offset Size Description
|
||||||
// Serial in libogc
|
// Serial in libogc
|
||||||
u8 serial[12]; //0x0000 12 ?
|
u8 serial[12]; //0x0000 12 ?
|
||||||
OSTime fmtTime; //0x000c 8 time of format (OSTime value)
|
u64 formatTime; //0x000c 8 time of format (OSTime value)
|
||||||
u8 SramBias[4]; //0x0014 4 sram bias at time of format
|
u8 SramBias[4]; //0x0014 4 sram bias at time of format
|
||||||
u8 SramLang[4]; //0x0018 4 sram language
|
u8 SramLang[4]; //0x0018 4 sram language
|
||||||
u8 Unk2[4]; //0x001c 4 ? almost always 0
|
u8 Unk2[4]; //0x001c 4 ? almost always 0
|
||||||
|
@ -99,8 +94,8 @@ private:
|
||||||
u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
|
u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
|
||||||
u8 Unused1[468]; //0x0026 468 unused (0xff)
|
u8 Unused1[468]; //0x0026 468 unused (0xff)
|
||||||
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
|
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
|
||||||
u8 CheckSum1[2]; //0x01fc 2 Checksum 1 (?)
|
u16 Checksum; //0x01fc 2 Additive Checksum
|
||||||
u8 CheckSum2[2]; //0x01fe 2 Checksum 2 (?)
|
u16 Checksum_Inv; //0x01fe 2 Inverse Checksum
|
||||||
u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff)
|
u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff)
|
||||||
} hdr;
|
} hdr;
|
||||||
|
|
||||||
|
@ -153,31 +148,38 @@ private:
|
||||||
DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127)
|
DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127)
|
||||||
u8 Padding[0x3a];
|
u8 Padding[0x3a];
|
||||||
u8 UpdateCounter[2];//0x1ffa 2 update Counter
|
u8 UpdateCounter[2];//0x1ffa 2 update Counter
|
||||||
u8 CheckSum1[2]; //0x1ffc 2 Checksum 1
|
u16 Checksum; //0x1ffc 2 Additive Checksum
|
||||||
u8 CheckSum2[2]; //0x1ffe 2 Checksum 2
|
u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum
|
||||||
} dir, dir_backup;
|
} dir, dir_backup;
|
||||||
|
|
||||||
struct BlockAlloc {
|
struct BlockAlloc {
|
||||||
u8 CheckSum1[2]; //0x0000 2 Checksum 1
|
u16 Checksum; //0x0000 2 Additive Checksum
|
||||||
u8 CheckSum2[2]; //0x0002 2 Checksum 2
|
u16 Checksum_Inv; //0x0002 2 Inverse Checksum
|
||||||
u8 UpdateCounter[2];//0x0004 2 update Counter
|
u8 UpdateCounter[2];//0x0004 2 update Counter
|
||||||
u8 FreeBlocks[2]; //0x0006 2 free Blocks
|
u8 FreeBlocks[2]; //0x0006 2 free Blocks
|
||||||
u8 LastAllocated[2];//0x0008 2 last allocated Block
|
u8 LastAllocated[2];//0x0008 2 last allocated Block
|
||||||
u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks
|
u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks
|
||||||
} bat,bat_backup;
|
} bat,bat_backup;
|
||||||
|
struct GCMC_Header
|
||||||
|
{
|
||||||
|
Header *hdr;
|
||||||
|
Directory *dir, *dir_backup;
|
||||||
|
BlockAlloc *bat, *bat_backup;
|
||||||
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
|
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
|
||||||
|
static void FormatInternal(GCMC_Header &GCP);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
|
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
|
||||||
bool IsValid() { return m_valid; }
|
bool IsValid() { return m_valid; }
|
||||||
bool IsAsciiEncoding();
|
bool IsAsciiEncoding();
|
||||||
bool Save();
|
bool Save();
|
||||||
bool Format(bool sjis = false, int slot = 0, u16 SizeMb = MemCard2043Mb);
|
bool Format(bool sjis = false, u16 SizeMb = MemCard2043Mb);
|
||||||
|
static bool Format(u8 * card_data, bool sjis = false, u16 SizeMb = MemCard2043Mb);
|
||||||
|
|
||||||
void calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2);
|
static void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum);
|
||||||
u32 TestChecksums();
|
u32 TestChecksums();
|
||||||
bool FixChecksums();
|
bool FixChecksums();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue