use BAT for block locations instead of assuming nonfragmented blocks *untested*

Signed-off-by: LPFaint99 <lpfaint99@gmail.com>
This commit is contained in:
LPFaint99 2012-02-06 01:52:13 -08:00
parent 8355363dcd
commit 1fe67e19ab
2 changed files with 90 additions and 21 deletions

View file

@ -543,24 +543,61 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const
return true; 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<u16> 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<GCMBlock> & Blocks) const u32 GCMemcard::GetSaveData(u8 index, std::vector<GCMBlock> & Blocks) const
{ {
if (!m_valid) if (!m_valid)
return NOMEMCARD; return NOMEMCARD;
u16 block = DEntry_FirstBlock(index); u16 block = DEntry_FirstBlock(index);
u16 saveLength = DEntry_BlockCount(index); u16 BlockCount = DEntry_BlockCount(index);
u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS;
if ((block == 0xFFFF) || (saveLength == 0xFFFF) if ((block == 0xFFFF) || (BlockCount == 0xFFFF))
|| (block + saveLength > memcardSize))
{ {
return FAIL; 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; return SUCCESS;
} }
@ -585,10 +622,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, i
} }
// find first free data block -- assume no freespace fragmentation // find first free data block -- assume no freespace fragmentation
int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); //int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS);
int firstFree1 = BE16(bat.LastAllocated) + 1; //int firstFree1 = BE16(bat.LastAllocated) + 1;
int firstFree2 = 0;
for (int i = 0; i < DIRLEN; i++)
/* for (int i = 0; i < DIRLEN; i++)
{ {
if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF)
{ {
@ -601,7 +640,8 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, i
} }
} }
firstFree1 = max<int>(firstFree1, firstFree2); firstFree1 = max<int>(firstFree1, firstFree2);
*/
u16 firstBlock = NextFreeBlock();
// find first free dir entry // find first free dir entry
int index = -1; int index = -1;
for (int i=0; i < DIRLEN; i++) for (int i=0; i < DIRLEN; i++)
@ -610,7 +650,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, i
{ {
index = i; index = i;
dir.Dir[i] = direntry; dir.Dir[i] = direntry;
*(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1); *(u16*)&dir.Dir[i].FirstBlock = BE16(firstBlock);
if (!remove) if (!remove)
{ {
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1;
@ -622,15 +662,22 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, i
int fileBlocks = BE16(direntry.BlockCount); int fileBlocks = BE16(direntry.BlockCount);
firstFree1 -= MC_FST_BLOCKS;
u16 nextBlock;
// keep assuming no freespace fragmentation, and copy over all the data // keep assuming no freespace fragmentation, and copy over all the data
for (int i = 0; i < fileBlocks; ++i) 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; bat_backup = bat;
u16 last = BE16(bat_backup.LastAllocated); /* u16 last = BE16(bat_backup.LastAllocated);
u16 i = (last - 4); u16 i = (last - 4);
int j = 2; int j = 2;
while(j < BE16(direntry.BlockCount) + 1) while(j < BE16(direntry.BlockCount) + 1)
@ -645,11 +692,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, i
{ {
bat_backup.Map[i++] = 0x0000; bat_backup.Map[i++] = 0x0000;
} }
*/
//update last allocated block //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 //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) if (!remove)
@ -666,7 +714,25 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
{ {
if (!m_valid) if (!m_valid)
return NOMEMCARD; 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 //error checking
u16 startingblock = 0; u16 startingblock = 0;
for (int i = 0; i < DIRLEN; i++) for (int i = 0; i < DIRLEN; i++)
@ -730,8 +796,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
} }
// increment update counter // increment update counter
*(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1);
*/
return SUCCESS;
} }
u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index)

View file

@ -55,6 +55,7 @@ enum
DENTRY_STRLEN = 0x20, DENTRY_STRLEN = 0x20,
DENTRY_SIZE = 0x40, DENTRY_SIZE = 0x40,
BLOCK_SIZE = 0x2000, BLOCK_SIZE = 0x2000,
BAT_SIZE = 0xFFB,
MemCard59Mb = 0x04, MemCard59Mb = 0x04,
MemCard123Mb = 0x08, MemCard123Mb = 0x08,
@ -162,7 +163,7 @@ private:
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[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks
} bat,bat_backup; } bat,bat_backup;
struct GCMC_Header struct GCMC_Header
{ {
@ -218,6 +219,9 @@ public:
std::string GetSaveComment2(u8 index) const; std::string GetSaveComment2(u8 index) const;
// Copies a DEntry from u8 index to DEntry& data // Copies a DEntry from u8 index to DEntry& data
bool GetDEntry(u8 index, DEntry &dest) const; 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 // assumes there's enough space in buffer
// old determines if function uses old or new method of copying data // old determines if function uses old or new method of copying data