From 1fe67e19ab8ee1dfb87df3d348270bd76eb5a9b5 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 01:52:13 -0800 Subject: [PATCH] use BAT for block locations instead of assuming nonfragmented blocks *untested* Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 105 +++++++++++++++++++++----- Source/Core/Core/Src/HW/GCMemcard.h | 6 +- 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 7a574b7106..2926017b2a 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -543,24 +543,61 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const return true; } +u16 GCMemcard::GetNextBlock(u16 Block) const +{ + if ((Block < MC_FST_BLOCKS) || (Block > maxBlock)) + return 0; + return Common::swap16(bat.Map[Block-MC_FST_BLOCKS]); +} + +u16 GCMemcard::NextFreeBlock(u16 StartingBlock) const +{ + for (u16 i = StartingBlock; i < BAT_SIZE; ++i) + if (bat.Map[i-MC_FST_BLOCKS] == 0) + return i; +} + +bool GCMemcard::ClearBlocks(u16 FirstBlock, u16 BlockCount) +{ + std::vector blocks; + while (FirstBlock != 0xFF && FirstBlock != 0) + { + blocks.push_back(FirstBlock); + FirstBlock = GetNextBlock(FirstBlock); + } + + if (FirstBlock > 0) + { + size_t length = blocks.size(); + if (length != BlockCount) + return false; + for (int i = 0; i < length; ++i) + bat.Map[blocks.at(i)-MC_FST_BLOCKS] = 0; + *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BlockCount); + } + return true; +} u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const { if (!m_valid) return NOMEMCARD; u16 block = DEntry_FirstBlock(index); - u16 saveLength = DEntry_BlockCount(index); + u16 BlockCount = DEntry_BlockCount(index); u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; - if ((block == 0xFFFF) || (saveLength == 0xFFFF) - || (block + saveLength > memcardSize)) + if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) { return FAIL; } - for (int i = 0; i < saveLength; ++i) + u16 nextBlock = block; + for (int i = 0; i < BlockCount; ++i) { - Blocks.push_back(mc_data_blocks[i + block-MC_FST_BLOCKS]); + if ((!nextBlock) || (nextBlock == 0xFFFF)) + return FAIL; + Blocks.push_back(mc_data_blocks[nextBlock-MC_FST_BLOCKS]); + nextBlock = GetNextBlock(nextBlock); } return SUCCESS; } @@ -585,10 +622,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i } // find first free data block -- assume no freespace fragmentation - int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - int firstFree1 = BE16(bat.LastAllocated) + 1; - int firstFree2 = 0; - for (int i = 0; i < DIRLEN; i++) + //int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); + //int firstFree1 = BE16(bat.LastAllocated) + 1; + + + +/* for (int i = 0; i < DIRLEN; i++) { if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) { @@ -601,7 +640,8 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i } } firstFree1 = max(firstFree1, firstFree2); - + */ + u16 firstBlock = NextFreeBlock(); // find first free dir entry int index = -1; for (int i=0; i < DIRLEN; i++) @@ -610,7 +650,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i { index = i; dir.Dir[i] = direntry; - *(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1); + *(u16*)&dir.Dir[i].FirstBlock = BE16(firstBlock); if (!remove) { dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; @@ -622,15 +662,22 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i int fileBlocks = BE16(direntry.BlockCount); - firstFree1 -= MC_FST_BLOCKS; + + u16 nextBlock; // keep assuming no freespace fragmentation, and copy over all the data for (int i = 0; i < fileBlocks; ++i) - { - mc_data_blocks[i + firstFree1] = saveBlocks[i]; + { + mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; + if (i == fileBlocks-1) + nextBlock = 0xFFFF; + else + nextBlock = NextFreeBlock(firstBlock+1); + bat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + firstBlock = nextBlock; } bat_backup = bat; - u16 last = BE16(bat_backup.LastAllocated); +/* u16 last = BE16(bat_backup.LastAllocated); u16 i = (last - 4); int j = 2; while(j < BE16(direntry.BlockCount) + 1) @@ -645,11 +692,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i { bat_backup.Map[i++] = 0x0000; } - + */ //update last allocated block - *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); +/* *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); +*/ //update freespace counter - *(u16*)&bat_backup.FreeBlocks = BE16(totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS); + *(u16*)&bat_backup.FreeBlocks = BE16(BE16(bat_backup.FreeBlocks) - fileBlocks); if (!remove) @@ -666,7 +714,25 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array { if (!m_valid) return NOMEMCARD; + if (index >= DIRLEN) + return DELETE_FAIL; + + dir_backup = dir; + bat_backup = bat; + u16 startingblock = BE16(dir.Dir[index].FirstBlock); + u16 numberofblocks = BE16(dir.Dir[index].BlockCount); + if (!ClearBlocks(startingblock, numberofblocks)) + return DELETE_FAIL; + + + memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE); + + *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); + *(u16*)&bat.UpdateCounter = BE16(BE16(bat.UpdateCounter) + 1); + + return SUCCESS; + /* //error checking u16 startingblock = 0; for (int i = 0; i < DIRLEN; i++) @@ -730,8 +796,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array } // increment update counter *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); - - return SUCCESS; + */ } u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index e1ab970053..e66f77887e 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -55,6 +55,7 @@ enum DENTRY_STRLEN = 0x20, DENTRY_SIZE = 0x40, BLOCK_SIZE = 0x2000, + BAT_SIZE = 0xFFB, MemCard59Mb = 0x04, MemCard123Mb = 0x08, @@ -162,7 +163,7 @@ private: u8 UpdateCounter[2];//0x0004 2 update Counter u8 FreeBlocks[2]; //0x0006 2 free Blocks u8 LastAllocated[2];//0x0008 2 last allocated Block - u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks + u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks } bat,bat_backup; struct GCMC_Header { @@ -218,6 +219,9 @@ public: std::string GetSaveComment2(u8 index) const; // Copies a DEntry from u8 index to DEntry& data bool GetDEntry(u8 index, DEntry &dest) const; + u16 GetNextBlock(u16 Block) const; + u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; + bool ClearBlocks(u16 StartingBlock, u16 Length); // assumes there's enough space in buffer // old determines if function uses old or new method of copying data