make working dir save to a platform specific file

fix a possible buffer overflow in MemcardManager when creating a gci savename
fix Previous Page button from being available after deleting the last save on page 2
remove magic numbers from GCMemcard

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3819 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
LPFaint99 2009-07-17 06:03:53 +00:00
parent 598d640042
commit 15d49e5afd
4 changed files with 113 additions and 87 deletions

View File

@ -132,7 +132,12 @@ bool DolphinApp::OnInit()
if (!noCheckForInstallDir)
{
char tmp[1024];
sprintf(tmp, "%s/.dolphinwd", (const char*)wxStandardPaths::Get().GetUserConfigDir().mb_str(wxConvUTF8));
sprintf(tmp, "%s/.dolphin%swd", (const char*)wxStandardPaths::Get().GetUserConfigDir().mb_str(wxConvUTF8),
#ifdef _M_IX86
"x32");
#else
"x64");
#endif
FILE* workingDir = fopen(tmp, "r");
if (!workingDir)
{
@ -174,7 +179,7 @@ bool DolphinApp::OnInit()
fclose(workingDir);
if (!wxSetWorkingDirectory(wxString::FromAscii(tmpChar)))
{
PanicAlert("set working directory failed");
INFO_LOG(CONSOLE, "set working directory failed");
}
delete [] tmpChar;
}

View File

@ -586,7 +586,8 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
case ID_SAVEEXPORT_B:
if (index != wxNOT_FOUND)
{
char tempC[36], tempC2[32];
char tempC[10 + DENTRY_STRLEN],
tempC2[DENTRY_STRLEN];
memoryCard[slot]->DEntry_GameCode(index,tempC);
memoryCard[slot]->DEntry_FileName(index,tempC2);
sprintf(tempC, "%s_%s.gci", tempC, tempC2);
@ -734,10 +735,10 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card)
}
int pagesMax = 128;
if (m_MemcardList[card]->usePages) pagesMax = (page[card] + 1) * itemsPerPage;
for (j = page[card] * itemsPerPage;(j < nFiles) && (j < pagesMax);j++)
for (j = page[card] * itemsPerPage;(j < nFiles) && (j < pagesMax); j++)
{
char title[32];
char comment[32];
char title[DENTRY_STRLEN];
char comment[DENTRY_STRLEN];
u16 blocks;
u16 firstblock;
@ -807,7 +808,12 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card)
if (m_MemcardList[card]->usePages)
{
if ((j == nFiles))
if (nFiles <= itemsPerPage)
{
m_PrevPage[card]->Disable();
m_MemcardList[card]->prevPage = false;
}
if (j == nFiles)
{
m_NextPage[card]->Disable();
m_MemcardList[card]->nextPage = false;

View File

@ -100,32 +100,32 @@ GCMemcard::GCMemcard(const char *filename)
}
}
fseek(mcd, 0x0000, SEEK_SET);
if (fread(&hdr, 1, 0x2000, mcd) != 0x2000)
fseek(mcd, 0, SEEK_SET);
if (fread(&hdr, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
{
fail = true;
PanicAlert("Failed to read header correctly\n(0x0000-0x1FFF)");
return;
}
if (fread(&dir, 1, 0x2000, mcd) != 0x2000)
if (fread(&dir, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
{
fail = true;
PanicAlert("Failed to read directory correctly\n(0x2000-0x3FFF)");
return;
}
if (fread(&dir_backup, 1, 0x2000, mcd) != 0x2000)
if (fread(&dir_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
{
fail = true;
PanicAlert("Failed to read directory backup correctly\n(0x4000-0x5FFF)");
return;
}
if (fread(&bat, 1, 0x2000, mcd) != 0x2000)
if (fread(&bat, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
{
fail = true;
PanicAlert("Failed to read block allocation table correctly\n(0x6000-0x7FFF)");
return;
}
if (fread(&bat_backup, 1, 0x2000, mcd) != 0x2000)
if (fread(&bat_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
{
fail = true;
PanicAlert("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)");
@ -193,13 +193,18 @@ GCMemcard::GCMemcard(const char *filename)
fseek(mcd, 0xa000, SEEK_SET);
u16 size = BE16(hdr.Size);
if ((size== 0x0080) || (size == 0x0040) ||
(size == 0x0020) || (size == 0x0010) ||
(size == 0x0008) || (size == 0x0004))
u16 sizeMb = BE16(hdr.SizeMb);
switch (sizeMb)
{
maxBlock = size * 0x10;
mc_data_size = (((u32)size * 16) - 5) * 0x2000;
case MemCard59Mb:
case MemCard123Mb:
case MemCard251Mb:
case Memcard507Mb:
case MemCard1019Mb:
case MemCard2043Mb:
{
maxBlock = (u32)sizeMb * MBIT_TO_BLOCKS;
mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE;
mc_data = new u8[mc_data_size];
size_t read = fread(mc_data, 1, mc_data_size, mcd);
@ -208,11 +213,11 @@ GCMemcard::GCMemcard(const char *filename)
fail = true;
PanicAlert("Failed to read save data\n(0xA000-)\nMemcard may be truncated");
}
break;
}
else
{
default:
fail = true;
PanicAlert("Memcard failed to load\n Card size is invalid (%04X)", size);
PanicAlert("Memcard failed to load\n Card size is invalid (%04X)", sizeMb);
}
}
@ -232,11 +237,11 @@ bool GCMemcard::Save()
bool completeWrite = true;
FILE *mcd=(FILE*)mcdFile;
fseek(mcd, 0, SEEK_SET);
if (fwrite(&hdr, 1, 0x2000, mcd) != 0x2000) completeWrite = false;
if (fwrite(&dir, 1, 0x2000, mcd) != 0x2000) completeWrite = false;
if (fwrite(&dir_backup, 1, 0x2000, mcd) != 0x2000) completeWrite = false;
if (fwrite(&bat, 1, 0x2000 ,mcd) != 0x2000) completeWrite = false;
if (fwrite(&bat_backup, 1, 0x2000, mcd) != 0x2000) completeWrite = false;
if (fwrite(&hdr, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
if (fwrite(&dir, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
if (fwrite(&dir_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
if (fwrite(&bat, 1, BLOCK_SIZE ,mcd) != BLOCK_SIZE) completeWrite = false;
if (fwrite(&bat_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
if (fwrite(mc_data, 1, mc_data_size, mcd) != mc_data_size) completeWrite = false;
return completeWrite;
}
@ -367,7 +372,7 @@ u8 GCMemcard::TitlePresent(DEntry d)
return i;
}
// DEntry functions, all take u8 index < 127
// DEntry functions, all take u8 index < DIRLEN (127)
// Functions that have ascii output take a char *buffer
bool GCMemcard::DEntry_GameCode(u8 index, char *buffer)
@ -403,7 +408,7 @@ bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer)
bool GCMemcard::DEntry_FileName(u8 index, char *buffer)
{
if (!mcdFile) return false;
memcpy (buffer, (const char*)dir.Dir[index].Filename, 32);
memcpy (buffer, (const char*)dir.Dir[index].Filename, DENTRY_STRLEN);
buffer[31] = 0;
return true;
}
@ -481,13 +486,13 @@ bool GCMemcard::DEntry_Comment1(u8 index, char* buffer)
if (!mcdFile) return false;
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS;
if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF))
{
buffer[0] = 0;
return false;
}
memcpy(buffer, mc_data + (DataBlock * 0x2000) + Comment1, 32);
memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN);
buffer[31] = 0;
return true;
}
@ -497,14 +502,14 @@ bool GCMemcard::DEntry_Comment2(u8 index, char* buffer)
if (!mcdFile) return false;
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
u32 Comment2 = Comment1 + 32;
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
u32 Comment2 = Comment1 + DENTRY_STRLEN;
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS;
if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF))
{
buffer[0] = 0;
return false;
}
memcpy(buffer, mc_data + (DataBlock * 0x2000) + Comment2, 32);
memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN);
buffer[31] = 0;
return true;
}
@ -523,7 +528,7 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
u16 block = DEntry_FirstBlock(index);
u16 saveLength = DEntry_BlockCount(index);
u16 memcardSize = BE16(hdr.Size) * 0x0010;
u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS;
if ((block == 0xFFFF) || (saveLength == 0xFFFF)
|| (block + saveLength > memcardSize))
@ -533,17 +538,17 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
if (!old)
{
memcpy(dest,mc_data + 0x2000*(block-5), saveLength*0x2000);
memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), saveLength * BLOCK_SIZE);
}
else
{
if (block == 0) return FAIL;
while (block != 0xffff)
{
memcpy(dest, mc_data + 0x2000 * (block - 5), 0x2000);
dest += 0x2000;
memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), BLOCK_SIZE);
dest += BLOCK_SIZE;
u16 nextblock = Common::swap16(bat.Map[block - 5]);
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;
@ -573,7 +578,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
}
// find first free data block -- assume no freespace fragmentation
int totalspace = (((u32)BE16(hdr.Size) * 16) - 5);
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++)
@ -592,7 +597,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
// find first free dir entry
int index = -1;
for (int i=0; i < 127; i++)
for (int i=0; i < DIRLEN; i++)
{
if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF)
{
@ -610,10 +615,10 @@ 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 - 5) * 0x2000;
u8 *destination = mc_data + (firstFree1 - MC_FST_BLOCKS) * BLOCK_SIZE;
int fileBlocks = BE16(direntry.BlockCount);
memcpy(destination, contents, 0x2000 * fileBlocks);
memcpy(destination, contents, BLOCK_SIZE * fileBlocks);
bat_backup = bat;
u16 last = BE16(bat_backup.LastAllocated);
u16 i = (last - 4);
@ -637,7 +642,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
bat_backup.LastAllocated[1] = u8(lastallocated);
//update freespace counter
int freespace1 = totalspace - firstFree1 - fileBlocks + 5;
int freespace1 = totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS;
bat_backup.FreeBlocks[0] = u8(freespace1 >> 8);
bat_backup.FreeBlocks[1] = u8(freespace1);
@ -671,7 +676,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
bat.LastAllocated[1] = (u8)block;
u8 nextIndex = index + 1;
memset(&(dir.Dir[index]), 0xFF, 0x40);
memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE);
while (nextIndex < DIRLEN)
{
@ -688,7 +693,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
u16 size = DEntry_BlockCount(nextIndex);
if (size != 0xFFFF)
{
tempSaveData = new u8[size * 0x2000];
tempSaveData = new u8[size * BLOCK_SIZE];
switch (DEntry_GetSaveData(nextIndex, tempSaveData, true))
{
case NOMEMCARD:
@ -701,7 +706,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
}
}
}
memset(&(dir.Dir[nextIndex]), 0xFF, 0x40);
memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE);
//Only call import file if DEntry_GetSaveData returns SUCCESS
if (tempSaveData != NULL)
{
@ -737,7 +742,7 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index)
u32 size = source.DEntry_BlockCount(index);
if (size == 0xFFFF) return INVALIDFILESIZE;
u8 *tempSaveData = new u8[size * 0x2000];
u8 *tempSaveData = new u8[size * BLOCK_SIZE];
switch (source.DEntry_GetSaveData(index, tempSaveData, true))
{
@ -801,11 +806,11 @@ u32 GCMemcard::ImportGci(const char *fileName, std::string fileName2)
DEntry *tempDEntry = new DEntry;
fread(tempDEntry, 1, 0x40, gci);
fread(tempDEntry, 1, DENTRY_SIZE, gci);
int fStart = (int) ftell(gci);
fseek(gci, 0, SEEK_END);
int length = (int) ftell(gci) - fStart;
fseek(gci, offset + 0x40, SEEK_SET);
fseek(gci, offset + DENTRY_SIZE, SEEK_SET);
switch(offset){
case GCS:
@ -814,7 +819,7 @@ u32 GCMemcard::ImportGci(const char *fileName, std::string fileName2)
// It is stored only within the corresponding GSV file.
// If the GCS file is added without using the GameSaves software,
// the value stored is always "1"
int blockCount = length / 0x2000;
int blockCount = length / BLOCK_SIZE;
tempDEntry->BlockCount[0] = u8(blockCount >> 8);
tempDEntry->BlockCount[1] = u8(blockCount);
}
@ -840,15 +845,15 @@ u32 GCMemcard::ImportGci(const char *fileName, std::string fileName2)
default:
break;
}
if (length != BE16(tempDEntry->BlockCount) * 0x2000)
if (length != BE16(tempDEntry->BlockCount) * BLOCK_SIZE)
{
return LENGTHFAIL;
}
if (ftell(gci) != offset + 0x40) // Verify correct file position
if (ftell(gci) != offset + DENTRY_SIZE) // Verify correct file position
{
return OPENFAIL;
}
u32 size = BE16((tempDEntry->BlockCount)) * 0x2000;
u32 size = BE16((tempDEntry->BlockCount)) * BLOCK_SIZE;
u8 *tempSaveData = new u8[size];
fread(tempSaveData, 1, size, gci);
fclose(gci);
@ -860,11 +865,11 @@ u32 GCMemcard::ImportGci(const char *fileName, std::string fileName2)
if (!gci2) return OPENFAIL;
fseek(gci2, 0, SEEK_SET);
if (fwrite(tempDEntry, 1, 0x40, gci2) != 0x40) completeWrite = false;
if (fwrite(tempDEntry, 1, DENTRY_SIZE, gci2) != DENTRY_SIZE) completeWrite = false;
int fileBlocks = BE16(tempDEntry->BlockCount);
fseek(gci2, 0x40, SEEK_SET);
fseek(gci2, DENTRY_SIZE, SEEK_SET);
if (fwrite(tempSaveData, 1, 0x2000 * fileBlocks, gci2) != (unsigned) (0x2000*fileBlocks))
if (fwrite(tempSaveData, 1, BLOCK_SIZE * fileBlocks, gci2) != (unsigned) (BLOCK_SIZE * fileBlocks))
completeWrite = false;
fclose(gci2);
if (completeWrite) ret = GCS;
@ -905,11 +910,11 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
DEntry tempDEntry;
if (!DEntry_Copy(index, tempDEntry)) return NOMEMCARD;
if (fwrite(&tempDEntry, 1, 0x40, gci) != 0x40) completeWrite = false;
if (fwrite(&tempDEntry, 1, DENTRY_SIZE, gci) != DENTRY_SIZE) completeWrite = false;
u32 size = DEntry_BlockCount(index);
if (size == 0xFFFF) return FAIL;
size *= 0x2000;
size *= BLOCK_SIZE;
u8 *tempSaveData = new u8[size];
switch(DEntry_GetSaveData(index, tempSaveData, true))
@ -925,7 +930,7 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
default:
break;
}
fseek(gci, 0x40, SEEK_SET);
fseek(gci, DENTRY_SIZE, SEEK_SET);
if (fwrite(tempSaveData, 1, size, gci) != size)
completeWrite = false;
fclose(gci);
@ -950,7 +955,7 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
return false;
u32 DataOffset = BE32(dir.Dir[index].ImageOffset);
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS;
if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF))
{
@ -961,14 +966,14 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
if (bnrFormat&1)
{
u8 *pxdata = (u8* )(mc_data +(DataBlock*0x2000) + DataOffset);
u16 *paldata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset + pixels);
u8 *pxdata = (u8* )(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset);
u16 *paldata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset + pixels);
decodeCI8image(buffer, pxdata, paldata, 96, 32);
}
else
{
u16 *pxdata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset);
u16 *pxdata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset);
decode5A3image(buffer, pxdata, 96, 32);
}
@ -993,14 +998,14 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
int bnrFormat = (flags&3);
u32 DataOffset = BE32(dir.Dir[index].ImageOffset);
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS;
if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF))
{
return 0;
}
u8* animData = (u8*)(mc_data +(DataBlock*0x2000) + DataOffset);
u8* animData = (u8*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset);
switch (bnrFormat)
{
@ -1073,11 +1078,11 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
return frames;
}
bool GCMemcard::Format( bool New, int slot, bool sjis, bool hdrOnly)
bool GCMemcard::Format(bool New, int slot, u16 SizeMb, bool sjis, bool hdrOnly)
{
//Currently only formats cards for slot A
u32 data_size = 0x2000 * (0x80 * 0x10 - 5);
u16 size = (u16)(((data_size / 0x2000) + 5) / 0x10);
u32 data_size = BLOCK_SIZE * (SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
SRAM m_SRAM;
FILE * pStream;
u64 time, rand;
@ -1088,7 +1093,7 @@ bool GCMemcard::Format( bool New, int slot, bool sjis, bool hdrOnly)
mc_data = new u8[mc_data_size];
}
// Only Format 16MB memcards for now
if (data_size != mc_data_size) return false;
if ((SizeMb != MemCard2043Mb) || (data_size != mc_data_size)) return false;
pStream = fopen(GC_SRAM_FILE, "rb");
if (pStream == NULL)
@ -1102,7 +1107,7 @@ bool GCMemcard::Format( bool New, int slot, bool sjis, bool hdrOnly)
time = CEXIIPL::GetGCTime();
rand = Common::swap64(time);
memset(&hdr, 0xFF, 0x2000);
memset(&hdr, 0xFF, BLOCK_SIZE);
for(int i = 0; i < 12; i++)
{
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
@ -1118,20 +1123,20 @@ bool GCMemcard::Format( bool New, int slot, bool sjis, bool hdrOnly)
*(u32*)&(hdr.Unk2) = Common::swap32(1); // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000;
// TODO: find out why memcard cares if component cable used for now set to one like main app
*(u16*)&(hdr.deviceID) = 0;
*(u16*)&(hdr.Size) = Common::swap16(size);
*(u16*)&(hdr.SizeMb) = Common::swap16(SizeMb);
*(u16*)&(hdr.Encoding) = Common::swap16(sjis ? 1 : 0);
if (!hdrOnly)
{
memset(&dir, 0xFF, 0x2000);
memset(&dir_backup, 0xFF, 0x2000);
memset(&dir, 0xFF, BLOCK_SIZE);
memset(&dir_backup, 0xFF, BLOCK_SIZE);
*(u16*)&dir.UpdateCounter = 0;
*(u16*)&dir_backup.UpdateCounter = Common::swap16(1);
memset(&bat, 0, 0x2000);
memset(&bat_backup, 0, 0x2000);
memset(&bat, 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(size * 0x10 - 5);
*(u16*)&bat.FreeBlocks = *(u16*)&bat_backup.FreeBlocks = Common::swap16(SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
*(u16*)&bat.LastAllocated = *(u16*)&bat_backup.LastAllocated = Common::swap16(4);
memset(mc_data, 0xFF, mc_data_size);
}

View File

@ -26,11 +26,11 @@
#define BE32(x) ((u32((x)[0])<<24) | (u32((x)[1])<<16) | (u32((x)[2])<<8) | u32((x)[3]))
#define BE16(x) ((u16((x)[0])<<8) | u16((x)[1]))
#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));
#define SLOT_A 0
#define SLOT_B 1
enum
{
SLOT_A = 0,
SLOT_B = 1,
GCI = 0,
SUCCESS,
NOMEMCARD,
@ -47,13 +47,23 @@ enum
GCSFAIL,
FAIL,
WRITEFAIL,
};
enum
{
MC_FST_BLOCKS = 0x05,
MBIT_TO_BLOCKS = 0x10,
DENTRY_STRLEN = 0x20,
DENTRY_SIZE = 0x40,
BLOCK_SIZE = 0x2000,
MemCard59Mb = 0x04,
MemCard123Mb = 0x08,
MemCard251Mb = 0x10,
Memcard507Mb = 0x20,
MemCard1019Mb = 0x40,
MemCard2043Mb = 0x80,
CI8SHARED = 1,
RGB5A3,
CI8
CI8,
};
class GCMemcard
@ -81,7 +91,7 @@ private:
u8 Unk2[4]; //0x001c 4 ? almost always 0
// end Serial in libogc
u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B
u8 Size[2]; //0x0022 2 size of memcard in Mbits
u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits
u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
u8 Unused1[468]; //0x0026 468 unused (0xff)
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
@ -105,7 +115,7 @@ private:
// 01 RGB5A3 banner
// 11 ? maybe ==01? haven't seen it
//
u8 Filename[32]; //0x08 0x20 filename
u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename
u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000
u8 ImageOffset[4]; //0x2c 0x04 image data offset
u8 IconFmt[2]; //0x30 0x02 icon gfx format (2bits per icon)
@ -164,7 +174,7 @@ public:
bool IsOpen();
bool Save();
bool Format(bool New = true, int slot = 0, bool sjis = false, bool hdrOnly = false);
bool Format(bool New = true, int slot = 0, u16 SizeMb = MemCard2043Mb, bool sjis = false, bool hdrOnly = false);
void calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2);
u32 TestChecksums();
@ -179,7 +189,7 @@ public:
// If title already on memcard returns index, otherwise returns -1
u8 TitlePresent(DEntry d);
// DEntry functions, all take u8 index < 127
// DEntry functions, all take u8 index < DIRLEN (127)
// Functions that have ascii output take a char *buffer
// buffer needs to be a char[5] or bigger