change the data section from a plain array to a vector of blocks (arrays of 0x2000)

Signed-off-by: LPFaint99 <lpfaint99@gmail.com>
This commit is contained in:
LPFaint99 2011-12-10 15:44:40 -08:00
parent dfe890e8f1
commit 8355363dcd
2 changed files with 91 additions and 95 deletions

View File

@ -63,7 +63,6 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height)
GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
: m_valid(false) : m_valid(false)
, m_fileName(filename) , m_fileName(filename)
, mc_data(NULL)
{ {
File::IOFile mcdFile(m_fileName, "r+b"); File::IOFile mcdFile(m_fileName, "r+b");
if (!mcdFile.IsOpen()) if (!mcdFile.IsOpen())
@ -209,16 +208,22 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
mcdFile.Seek(0xa000, SEEK_SET); mcdFile.Seek(0xa000, SEEK_SET);
maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE; mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS);
mc_data = new u8[mc_data_size];
if (mcdFile.ReadBytes(mc_data, mc_data_size))
{
m_valid = true; m_valid = true;
for (u32 i = MC_FST_BLOCKS; i < maxBlock; ++i)
{
GCMBlock b;
if (mcdFile.ReadBytes(b.block, BLOCK_SIZE))
{
mc_data_blocks.push_back(b);
} }
else else
{ {
PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated"); PanicAlertT("Failed to read block %d of the save data\nMemcard may be truncated\nFilePosition:%llx", i, mcdFile.Tell());
m_valid = false;
break;
}
} }
mcdFile.Close(); mcdFile.Close();
@ -239,7 +244,10 @@ bool GCMemcard::Save()
mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE);
mcdFile.WriteBytes(&bat, BLOCK_SIZE); mcdFile.WriteBytes(&bat, BLOCK_SIZE);
mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE);
mcdFile.WriteBytes(mc_data, mc_data_size); for (int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i)
{
mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE);
}
return mcdFile.Close(); return mcdFile.Close();
} }
@ -373,6 +381,7 @@ bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const
filename = std::string((char*)dir.Dir[index].Gamecode, 4) + '_' + (char*)dir.Dir[index].Filename + ".gci"; filename = std::string((char*)dir.Dir[index].Gamecode, 4) + '_' + (char*)dir.Dir[index].Filename + ".gci";
return true; return true;
} }
// DEntry functions, all take u8 index < DIRLEN (127) // DEntry functions, all take u8 index < DIRLEN (127)
// Functions that have ascii output take a char *buffer // Functions that have ascii output take a char *buffer
@ -446,7 +455,7 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const
u16 GCMemcard::DEntry_AnimSpeed(u8 index) const u16 GCMemcard::DEntry_AnimSpeed(u8 index) const
{ {
if (!m_valid || index > DIRLEN) if (!m_valid || index > DIRLEN)
return 0; return 0xFF;
return BE16(dir.Dir[index].AnimSpeed); return BE16(dir.Dir[index].AnimSpeed);
} }
@ -508,7 +517,7 @@ std::string GCMemcard::GetSaveComment1(u8 index) const
{ {
return ""; return "";
} }
return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN); return std::string((const char *)mc_data_blocks[DataBlock].block + Comment1, DENTRY_STRLEN);
} }
std::string GCMemcard::GetSaveComment2(u8 index) const std::string GCMemcard::GetSaveComment2(u8 index) const
@ -523,7 +532,7 @@ std::string GCMemcard::GetSaveComment2(u8 index) const
{ {
return ""; return "";
} }
return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN); return std::string((const char *)mc_data_blocks[DataBlock].block + Comment2, DENTRY_STRLEN);
} }
bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const
@ -534,7 +543,7 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const
return true; return true;
} }
u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) const u32 GCMemcard::GetSaveData(u8 index, std::vector<GCMBlock> & Blocks) const
{ {
if (!m_valid) if (!m_valid)
return NOMEMCARD; return NOMEMCARD;
@ -549,31 +558,15 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) const
return FAIL; return FAIL;
} }
if (!old) for (int i = 0; i < saveLength; ++i)
{ {
memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), saveLength * BLOCK_SIZE); Blocks.push_back(mc_data_blocks[i + block-MC_FST_BLOCKS]);
}
else
{
if (block == 0) return FAIL;
while (block != 0xffff)
{
memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), BLOCK_SIZE);
dest += BLOCK_SIZE;
u16 nextblock = Common::swap16(bat.Map[block - MC_FST_BLOCKS]);
if (block + saveLength != memcardSize && nextblock > 0)
{//Fixes for older memcards that were not initialized with FF
block = nextblock;
}
else break;
}
} }
return SUCCESS; return SUCCESS;
} }
// End DEntry functions // End DEntry functions
u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, int remove)
{ {
if (!m_valid) if (!m_valid)
return NOMEMCARD; return NOMEMCARD;
@ -627,11 +620,15 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
} }
} }
// keep assuming no freespace fragmentation, and copy over all the data
u8 *destination = mc_data + (firstFree1 - MC_FST_BLOCKS) * BLOCK_SIZE;
int fileBlocks = BE16(direntry.BlockCount); int fileBlocks = BE16(direntry.BlockCount);
memcpy(destination, contents, BLOCK_SIZE * fileBlocks); firstFree1 -= MC_FST_BLOCKS;
// 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];
}
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);
@ -694,34 +691,31 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
{ {
DEntry tempDEntry; DEntry tempDEntry;
GetDEntry(nextIndex, tempDEntry); GetDEntry(nextIndex, tempDEntry);
u8 * tempSaveData = NULL; std::vector<GCMBlock> saveData;
u16 size = 0;
//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*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry.BlockCount)); *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry.BlockCount));
u16 size = DEntry_BlockCount(nextIndex); size = DEntry_BlockCount(nextIndex);
if (size != 0xFFFF) if (size != 0xFFFF)
{ {
tempSaveData = new u8[size * BLOCK_SIZE]; saveData.reserve(size);
switch (DEntry_GetSaveData(nextIndex, tempSaveData, true)) switch (GetSaveData(nextIndex, saveData))
{ {
case NOMEMCARD: case NOMEMCARD:
delete[] tempSaveData;
tempSaveData = NULL;
break; break;
case FAIL: case FAIL:
delete[] tempSaveData;
return FAIL; return FAIL;
} }
} }
} }
memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE); memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE);
//Only call import file if DEntry_GetSaveData returns SUCCESS //Only call import file if GetSaveData returns SUCCESS
if (tempSaveData != NULL) if (saveData.size() == size)
{ {
ImportFile(tempDEntry, tempSaveData, blocks_left); ImportFile(tempDEntry, saveData, blocks_left);
delete[] tempSaveData;
} }
nextIndex++; nextIndex++;
@ -751,20 +745,17 @@ u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index)
u32 size = source.DEntry_BlockCount(index); u32 size = source.DEntry_BlockCount(index);
if (size == 0xFFFF) return INVALIDFILESIZE; if (size == 0xFFFF) return INVALIDFILESIZE;
u8 *tempSaveData = new u8[size * BLOCK_SIZE];
switch (source.DEntry_GetSaveData(index, tempSaveData, true)) std::vector<GCMBlock> saveData;
saveData.reserve(size);
switch (source.GetSaveData(index, saveData))
{ {
case FAIL: case FAIL:
delete[] tempSaveData;
return FAIL; return FAIL;
case NOMEMCARD: case NOMEMCARD:
delete[] tempSaveData;
return NOMEMCARD; return NOMEMCARD;
default: default:
u32 ret = ImportFile(tempDEntry, tempSaveData, 0); return ImportFile(tempDEntry, saveData, 0);
delete[] tempSaveData;
return ret;
} }
} }
@ -828,9 +819,16 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s
if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position
return OPENFAIL; return OPENFAIL;
u32 size = BE16((tempDEntry.BlockCount)) * BLOCK_SIZE; u32 size = BE16((tempDEntry.BlockCount));
u8 *tempSaveData = new u8[size]; std::vector<GCMBlock> saveData;
gci.ReadBytes(tempSaveData, size); saveData.reserve(size);
for (int i = 0; i < size; ++i)
{
GCMBlock b;
gci.ReadBytes(b.block, BLOCK_SIZE);
saveData.push_back(b);
}
u32 ret; u32 ret;
if (!outputFile.empty()) if (!outputFile.empty())
{ {
@ -838,7 +836,6 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s
bool completeWrite = true; bool completeWrite = true;
if (!gci2) if (!gci2)
{ {
delete[] tempSaveData;
return OPENFAIL; return OPENFAIL;
} }
gci2.Seek(0, SEEK_SET); gci2.Seek(0, SEEK_SET);
@ -848,30 +845,32 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s
int fileBlocks = BE16(tempDEntry.BlockCount); int fileBlocks = BE16(tempDEntry.BlockCount);
gci2.Seek(DENTRY_SIZE, SEEK_SET); gci2.Seek(DENTRY_SIZE, SEEK_SET);
if (!gci2.WriteBytes(tempSaveData, BLOCK_SIZE * fileBlocks)) for (int i = 0; i < fileBlocks; ++i)
{
if (!gci2.WriteBytes(saveData[i].block, BLOCK_SIZE))
completeWrite = false; completeWrite = false;
}
if (completeWrite) if (completeWrite)
ret = GCS; ret = GCS;
else else
ret = WRITEFAIL; ret = WRITEFAIL;
} }
else else
ret = ImportFile(tempDEntry, tempSaveData, 0); ret = ImportFile(tempDEntry, saveData, 0);
delete[] tempSaveData;
return ret; return ret;
} }
u32 GCMemcard::ExportGci(u8 index, const char* fileName, const std::string &directory) const u32 GCMemcard::ExportGci(u8 index, const char *fileName, const std::string &directory) const
{ {
File::IOFile gci; File::IOFile gci;
int offset = GCI; int offset = GCI;
if (!strcasecmp(fileName, ".")) if (!fileName)
{ {
if (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF) return SUCCESS; std::string gciFilename;
if (!GCI_FileName(index, gciFilename)) return SUCCESS;
std::string outpuName = directory + DIR_SEP + DEntry_GameCode(index) + '_' + (char*)dir.Dir[index].Filename + ".gci"; gci.Open(directory + DIR_SEP + gciFilename, "wb");
gci.Open(outpuName, "wb");
} }
else else
{ {
@ -926,23 +925,21 @@ u32 GCMemcard::ExportGci(u8 index, const char* fileName, const std::string &dire
return FAIL; return FAIL;
} }
size *= BLOCK_SIZE; std::vector<GCMBlock> saveData;
u8 *tempSaveData = new u8[size]; saveData.reserve(size);
switch(DEntry_GetSaveData(index, tempSaveData, true)) switch(GetSaveData(index, saveData))
{ {
case FAIL: case FAIL:
delete[] tempSaveData;
return FAIL; return FAIL;
case NOMEMCARD: case NOMEMCARD:
delete[] tempSaveData;
return NOMEMCARD; return NOMEMCARD;
} }
gci.Seek(DENTRY_SIZE + offset, SEEK_SET); gci.Seek(DENTRY_SIZE + offset, SEEK_SET);
gci.WriteBytes(tempSaveData, size); for (int i = 0; i < size; ++i)
{
delete[] tempSaveData; gci.WriteBytes(saveData[i].block, BLOCK_SIZE);
}
if (gci.IsGood()) if (gci.IsGood())
return SUCCESS; return SUCCESS;
@ -1013,14 +1010,14 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const
if (bnrFormat&1) if (bnrFormat&1)
{ {
u8 *pxdata = (u8* )(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); u8 *pxdata = (u8* )(mc_data_blocks[DataBlock].block + DataOffset);
u16 *paldata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset + pixels); u16 *paldata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset + pixels);
decodeCI8image(buffer, pxdata, paldata, 96, 32); decodeCI8image(buffer, pxdata, paldata, 96, 32);
} }
else else
{ {
u16 *pxdata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); u16 *pxdata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset);
decode5A3image(buffer, pxdata, 96, 32); decode5A3image(buffer, pxdata, 96, 32);
} }
@ -1053,7 +1050,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
return 0; return 0;
} }
u8* animData = (u8*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); u8* animData = (u8*)(mc_data_blocks[DataBlock].block + DataOffset);
switch (bnrFormat) switch (bnrFormat)
{ {
@ -1169,17 +1166,13 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb)
m_sizeMb = SizeMb; m_sizeMb = SizeMb;
maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
if (mc_data) mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS);
for (u32 i = 0; i < (maxBlock - MC_FST_BLOCKS); ++i)
{ {
delete mc_data; GCMBlock b;
mc_data = NULL; mc_data_blocks.push_back(b);
} }
mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
mc_data = new u8[mc_data_size];
if (!mc_data)
return false;
memset(mc_data, 0xFF, mc_data_size);
m_valid = true; m_valid = true;
return Save(); return Save();

View File

@ -76,11 +76,14 @@ private:
std::string m_fileName; std::string m_fileName;
u32 maxBlock; u32 maxBlock;
u32 mc_data_size;
u8* mc_data;
u16 m_sizeMb; u16 m_sizeMb;
struct GCMBlock
{
GCMBlock(){erase();}
void erase() {memset(block, 0xFF, BLOCK_SIZE);}
u8 block[BLOCK_SIZE];
};
std::vector<GCMBlock> mc_data_blocks;
#pragma pack(push,1) #pragma pack(push,1)
struct Header { //Offset Size Description struct Header { //Offset Size Description
// Serial in libogc // Serial in libogc
@ -220,11 +223,11 @@ public:
// old determines if function uses old or new method of copying data // old determines if function uses old or new method of copying data
// some functions only work with old way, some only work with new way // some functions only work with old way, some only work with new way
// TODO: find a function that works for all calls or split into 2 functions // TODO: find a function that works for all calls or split into 2 functions
u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old) const; u32 GetSaveData(u8 index, std::vector<GCMBlock> &saveBlocks) const;
// adds the file to the directory and copies its contents // adds the file to the directory and copies its contents
// if remove > 0 it will pad bat.map with 0's sizeof remove // if remove > 0 it will pad bat.map with 0's sizeof remove
u32 ImportFile(DEntry& direntry, u8* contents, int remove); u32 ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks, int remove);
// delete a file from the directory // delete a file from the directory
u32 RemoveFile(u8 index); u32 RemoveFile(u8 index);