ImportFile and RemoveFile "fixed", should not cause corruption anymore, but still needs more work

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1098 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
LPFaint99 2008-11-08 20:34:43 +00:00
parent 8684b734e8
commit d2bbd6bda2
4 changed files with 350 additions and 356 deletions

View File

@ -72,8 +72,8 @@ wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, int width, int height
BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) BEGIN_EVENT_TABLE(CMemcardManager, wxDialog)
EVT_CLOSE(CMemcardManager::OnClose) EVT_CLOSE(CMemcardManager::OnClose)
EVT_BUTTON(ID_COPYLEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_COPYTOLEFT,CMemcardManager::CopyDeleteClick)
EVT_BUTTON(ID_COPYRIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_COPYTORIGHT,CMemcardManager::CopyDeleteClick)
EVT_BUTTON(ID_FIXCHECKSUM,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_FIXCHECKSUM,CMemcardManager::CopyDeleteClick)
EVT_BUTTON(ID_DELETELEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETELEFT,CMemcardManager::CopyDeleteClick)
EVT_BUTTON(ID_DELETERIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETERIGHT,CMemcardManager::CopyDeleteClick)
@ -111,8 +111,8 @@ CMemcardManager::~CMemcardManager()
void CMemcardManager::CreateGUIControls() void CMemcardManager::CreateGUIControls()
{ {
// buttons // buttons
m_CopyLeft = new wxButton(this, ID_COPYLEFT, wxT("<-Copy<-"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_CopyToLeft = new wxButton(this, ID_COPYTOLEFT, wxT("<-Copy<-"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_CopyRight = new wxButton(this, ID_COPYRIGHT, wxT("->Copy->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_CopyToRight = new wxButton(this, ID_COPYTORIGHT, wxT("->Copy->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_FixChecksum = new wxButton(this, ID_FIXCHECKSUM, wxT("<-Fix\nChecksum"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_FixChecksum = new wxButton(this, ID_FIXCHECKSUM, wxT("<-Fix\nChecksum"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
@ -150,8 +150,8 @@ void CMemcardManager::CreateGUIControls()
wxBoxSizer* sButtons; wxBoxSizer* sButtons;
sButtons = new wxBoxSizer(wxVERTICAL); sButtons = new wxBoxSizer(wxVERTICAL);
sButtons->AddStretchSpacer(2); sButtons->AddStretchSpacer(2);
sButtons->Add(m_CopyLeft, 0, wxEXPAND, 5); sButtons->Add(m_CopyToLeft, 0, wxEXPAND, 5);
sButtons->Add(m_CopyRight, 0, wxEXPAND, 5); sButtons->Add(m_CopyToRight, 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1); sButtons->AddStretchSpacer(1);
sButtons->Add(m_FixChecksum, 0, wxEXPAND, 5); sButtons->Add(m_FixChecksum, 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1); sButtons->AddStretchSpacer(1);
@ -206,22 +206,25 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
int index1 = m_MemcardList[1]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); int index1 = m_MemcardList[1]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
int slot = 1; int slot = 1;
int index2 = index1; int index2 = index1;
char * fileName2 = NULL; std::string fileName2("");
int freeblocks = 0;
switch(event.GetId()) switch (event.GetId())
{ {
case ID_COPYLEFT: case ID_COPYTOLEFT:
slot=0; if ((index1 != -1) && (memoryCard[0] != NULL))
index2 = index0;
case ID_COPYRIGHT:
if ((index2 != -1) && (memoryCard[slot] != NULL))
{ {
int slot2; memoryCard[0]->CopyFrom(*memoryCard[1], index1);
slot == 0 ? slot2=1:slot2=0; memoryCard[0]->Save();
memoryCard[slot]->CopyFrom(*memoryCard[slot2], index2); ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0);
memoryCard[slot]->Save(); }
slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) break;
: ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); case ID_COPYTORIGHT:
if ((index0 != -1) && (memoryCard[1] != NULL))
{
memoryCard[1]->CopyFrom(*memoryCard[0], index0);
memoryCard[1]->Save();
ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1);
} }
break; break;
case ID_FIXCHECKSUM: case ID_FIXCHECKSUM:
@ -234,11 +237,12 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
} }
break; break;
case ID_CONVERTTOGCI: case ID_CONVERTTOGCI:
fileName2 = new char; fileName2 = "convert";
case ID_SAVEIMPORTLEFT: case ID_SAVEIMPORTLEFT:
slot = 0; slot = 0;
case ID_SAVEIMPORTRIGHT: case ID_SAVEIMPORTRIGHT:
if (memoryCard[slot] != NULL || fileName2 != NULL) if (memoryCard[slot] != NULL || !fileName2.empty())
{ {
wxString temp = wxFileSelector(_T("Select the GCI file to import"), wxString temp = wxFileSelector(_T("Select the GCI file to import"),
wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format
@ -249,10 +253,10 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
"Datel MaxDrive/Pro files(*.sav)|*.sav"), "Datel MaxDrive/Pro files(*.sav)|*.sav"),
wxFileSelectorDefaultWildcardStr, wxFileSelectorDefaultWildcardStr,
wxFileSelectorDefaultWildcardStr wxFileSelectorDefaultWildcardStr
), ),
wxFD_OPEN | wxFD_FILE_MUST_EXIST); wxFD_OPEN | wxFD_FILE_MUST_EXIST);
const char * fileName = temp.ToAscii(); const char * fileName = temp.ToAscii();
if (*fileName2 != NULL && !temp.empty()) if (!temp.empty() && !fileName2.empty())
{ {
wxString temp2 = wxFileSelector(_T("Save GCI as.."), wxString temp2 = wxFileSelector(_T("Save GCI as.."),
wxEmptyString, wxEmptyString, _T(".gci"), wxString::Format wxEmptyString, wxEmptyString, _T(".gci"), wxString::Format
@ -262,8 +266,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
wxFileSelectorDefaultWildcardStr wxFileSelectorDefaultWildcardStr
), ),
wxFD_OVERWRITE_PROMPT|wxFD_SAVE); wxFD_OVERWRITE_PROMPT|wxFD_SAVE);
delete fileName2; fileName2 = temp2.mb_str();
fileName2 = (char*)temp2.ToAscii();
} }
if (temp.length() > 0) if (temp.length() > 0)
{ {
@ -288,6 +291,26 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
" does not have a valid extension"), wxT("Error"), " does not have a valid extension"), wxT("Error"),
wxOK|wxICON_ERROR); wxOK|wxICON_ERROR);
break; break;
case GCS:
wxMessageBox(wxT("File converted to .gci"),
wxT("Success"),wxOK);
break;
case OUTOFBLOCKS:
freeblocks = BE16(memoryCard[slot]->bat.FreeBlocks);
{
wxString Foobar;
Foobar.Printf("Only %d blocks available", freeblocks);
wxMessageBox(Foobar,wxT("Failure"),wxOK);
}
break;
case OUTOFDIRENTRIES:
wxMessageBox(wxT("No free dir index entries"),
wxT("Failure"),wxOK);
break;
case NOMEMCARD:
wxMessageBox(wxT("File is not recognized as a memcard"),
wxT("Failure"),wxOK);
break;
default: default:
memoryCard[slot]->Save(); memoryCard[slot]->Save();
slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1)

View File

@ -26,7 +26,7 @@
#include <wx/imaglist.h> #include <wx/imaglist.h>
#include "MemoryCards/GCMemcard.h" #include "MemoryCards/GCMemcard.h"
#define BE16(x) ((u16((x)[0])<<8) | u16((x)[1]))
#undef MEMCARD_MANAGER_STYLE #undef MEMCARD_MANAGER_STYLE
#define MEMCARD_MANAGER_STYLE wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | wxMAXIMIZE_BOX #define MEMCARD_MANAGER_STYLE wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | wxMAXIMIZE_BOX
@ -35,7 +35,7 @@ class CMemcardManager
{ {
public: public:
CMemcardManager(wxWindow *parent, wxWindowID id = 1, const wxString& title = wxT("Memory Card Manager WARNING-Make backups before using, will probably mangle stuff!"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = MEMCARD_MANAGER_STYLE); CMemcardManager(wxWindow *parent, wxWindowID id = 1, const wxString& title = wxT("Memory Card Manager WARNING-Make backups before using, should be fixed but could mangle stuff!"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = MEMCARD_MANAGER_STYLE);
virtual ~CMemcardManager(); virtual ~CMemcardManager();
private: private:
@ -43,8 +43,8 @@ class CMemcardManager
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
wxBoxSizer *sMain; wxBoxSizer *sMain;
wxButton *m_CopyLeft; wxButton *m_CopyToLeft;
wxButton *m_CopyRight; wxButton *m_CopyToRight;
wxButton *m_FixChecksum; wxButton *m_FixChecksum;
wxButton *m_SaveImportLeft; wxButton *m_SaveImportLeft;
wxButton *m_SaveExportLeft; wxButton *m_SaveExportLeft;
@ -62,8 +62,8 @@ class CMemcardManager
enum enum
{ {
ID_COPYRIGHT = 1000, ID_COPYTORIGHT = 1000,
ID_COPYLEFT, ID_COPYTOLEFT,
ID_FIXCHECKSUM, ID_FIXCHECKSUM,
ID_DELETERIGHT, ID_DELETERIGHT,
ID_DELETELEFT, ID_DELETELEFT,

View File

@ -20,7 +20,6 @@
#endif #endif
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include "wx/ffile.h"
#include "GCMemcard.h" #include "GCMemcard.h"
@ -74,11 +73,11 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
u32 GCMemcard::GetNumFiles() u32 GCMemcard::GetNumFiles()
{ {
if(!mcdFile) return 0; if (!mcdFile) return 0;
int j =0; int j = 0;
for(int i=0;i<126;i++) for (int i = 0; i < 127; i++)
{ {
if(BE32(dir.Dir[i].Gamecode)!=0xFFFFFFFF) if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF)
j++; j++;
} }
return j; return j;
@ -86,285 +85,254 @@ u32 GCMemcard::GetNumFiles()
bool GCMemcard::RemoveFile(u32 index) //index in the directory array bool GCMemcard::RemoveFile(u32 index) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
//backup the directory and bat (not really needed here but meh :P //backup the directory and bat (not really needed here but meh :P
dir_backup=dir; dir_backup = dir;
bat_backup=bat; bat_backup = bat;
int totalspace = (((u32)BE16(hdr.Size)*16)-5);
//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); int block = BE16(dir.Dir[index].FirstBlock);
do bat.LastAllocated[0] = (u8)((block - 1) >> 8);
bat.LastAllocated[1] = (u8)(block - 1);
int i = index + 1;
memset(&(dir.Dir[index]), 0xFF, 0x40);
while (i < 127)
{ {
int cbi = block-5; DEntry * d = new DEntry;
int nextblock=bswap16(bat.Map[cbi]); GetFileInfo(i, *d);
//assert(nextblock!=0); u8 *t = NULL;
if(nextblock==0) //Only get file data if it is a valid dir entry
if (BE16(d->FirstBlock) != 0xFFFF)
{ {
nextblock = block+1; u16 freeBlock= BE16(bat.FreeBlocks) - BE16(d->BlockCount);
bat.FreeBlocks[0] = u8(freeBlock >> 8);
bat.FreeBlocks[1] = u8(freeBlock);
t = new u8[GetFileSize(i) * 0x2000];
if (!GetFileData(i, t, true))
{
delete[] t;
}
} }
memset(&(dir.Dir[i]), 0xFF, 0x40);
bat.Map[cbi]=0; //Only call import file if Get File Data returns true
if (t)
block=nextblock;
blocks_left--;
}
while((block!=0xffff)&&(blocks_left>0));
//delete directory entry
for(int i=index;i<125;i++)
{
dir.Dir[i]=dir.Dir[i+1];
}
memset(&(dir.Dir[125]),0xFF,sizeof(DEntry));
//pack blocks to remove free space partitioning, assume no fragmentation.
u8 *mc_data2 = new u8[mc_data_size];
int firstFree=0;
for(int i=0;i<126;i++)
{
if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF)
{ {
break; ImportFile(*d, t, blocks_left);
delete[] t;
} }
delete d;
i++;
int fb = BE16(dir.Dir[i].FirstBlock);
int bc = BE16(dir.Dir[i].BlockCount);
u8* src = mc_data + (fb-5)*0x2000;
u8* dst = mc_data2 + firstFree*0x2000;
memcpy(dst,src,bc*0x2000);
for(int j=0;j<bc;j++)
{
bat.Map[firstFree+j] = bswap16(u16(firstFree+j+6));
}
bat.Map[firstFree+bc-1] = 0xFFFF;
dir.Dir[i].FirstBlock[0] = u8((firstFree+5)>>8);
dir.Dir[i].FirstBlock[1] = u8((firstFree+5));
firstFree += bc;
} }
for(int j=firstFree;j<totalspace;j++) // increment update counter
{ int updateCtr = BE16(dir.UpdateCounter) + 1;
bat.Map[j] = 0; dir.UpdateCounter[0] = u8(updateCtr >> 8);
}
firstFree+=4;
bat.LastAllocated[0] = u8(firstFree>>8);
bat.LastAllocated[1] = u8(firstFree);
delete [] mc_data;
mc_data = mc_data2;
//--
//update freespace counter
int freespace1 = totalspace - firstFree;
bat.FreeBlocks[0] = u8(freespace1>>8);
bat.FreeBlocks[1] = u8(freespace1);
// ... and update counter
int updateCtr = BE16(dir.UpdateCounter)+1;
dir.UpdateCounter[0] = u8(updateCtr>>8);
dir.UpdateCounter[1] = u8(updateCtr); dir.UpdateCounter[1] = u8(updateCtr);
//fix checksums
u16 csum1=0,csum2=0; FixChecksums();
calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); Save();
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*)(((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);
dir_backup=dir;
bat_backup=bat;
return true; return true;
} }
u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents) u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
{ {
if(!mcdFile) return 0; // TODO: add a check for existing game id
// so that only one save per title is allowed
// until then any particular title will always use the first save
if (!mcdFile) return NOMEMCARD;
if(BE16(bat.FreeBlocks)<BE16(direntry.BlockCount)) if (GetNumFiles() >= 127)
{ {
return 0; return OUTOFDIRENTRIES;
}
if (BE16(bat.FreeBlocks) < BE16(direntry.BlockCount))
{
return OUTOFBLOCKS;
} }
// find first free data block -- assume no freespace fragmentation // find first free data block -- assume no freespace fragmentation
int totalspace = (((u32)BE16(hdr.Size)*16)-5); int totalspace = (((u32)BE16(hdr.Size) * 16) - 5);
int firstFree1 = BE16(bat.LastAllocated)+1;
int firstFree1 = BE16(bat.LastAllocated) + 1;
int firstFree2 = 0; int firstFree2 = 0;
for(int i=0;i<totalspace;i++) for (int i = 0; i < 126; i++)
{ {
if(bat.Map[i]==0) if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF)
{
firstFree2=i+5;
break;
}
}
int firstFree3 = 0;
for(int i=0;i<126;i++)
{
if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF)
{ {
break; break;
} }
else else
{ {
firstFree3 = max<int>(firstFree3,(int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount))); firstFree2 = max<int>(firstFree2,
(int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount)));
} }
} }
firstFree1 = max<int>(firstFree1, max<int>(firstFree3, firstFree2)); firstFree1 = max<int>(firstFree1, firstFree2);
if(firstFree1>=126)
{
// TODO: show messagebox about the error
return 0;
}
// find first free dir entry // find first free dir entry
int index=-1; int index = -1;
for(int i=0;i<127;i++) for (int i=0; i < 127; i++)
{ {
if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF) if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF)
{ {
index=i; index = i;
dir.Dir[i] = direntry; dir.Dir[i] = direntry;
dir.Dir[i].FirstBlock[0] = u8(firstFree1>>8); dir.Dir[i].FirstBlock[0] = u8(firstFree1 >> 8);
dir.Dir[i].FirstBlock[1] = u8(firstFree1); dir.Dir[i].FirstBlock[1] = u8(firstFree1);
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; if (!remove)
{
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1;
}
dir_backup = dir;
break; break;
} }
} }
// keep assuming no freespace fragmentation, and copy over all the data // keep assuming no freespace fragmentation, and copy over all the data
u8*destination = mc_data + (firstFree1-5)*0x2000; u8*destination = mc_data + (firstFree1 - 5) * 0x2000;
int fileBlocks=BE16(direntry.BlockCount); int fileBlocks = BE16(direntry.BlockCount);
memcpy(destination,contents,0x2000*fileBlocks); memcpy(destination, contents, 0x2000 * fileBlocks);
bat_backup = bat;
u16 last = BE16(bat_backup.LastAllocated);
u16 i = (last - 4);
int j = 2;
while(j < BE16(direntry.BlockCount) + 1)
{
bat_backup.Map[i] = bswap16(last + (u16)j);
i++;
j++;
}
bat_backup.Map[i++] = 0xFFFF;
//Set bat.map to 0 for each block that was removed
for (int j = 0; j < remove; j++)
{
bat_backup.Map[i++] = 0x0000;
}
//update last allocated block
int lastallocated = 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; int freespace1 = totalspace - firstFree1 - fileBlocks + 5;
bat.FreeBlocks[0] = u8(freespace1>>8); bat_backup.FreeBlocks[0] = u8(freespace1 >> 8);
bat.FreeBlocks[1] = u8(freespace1); bat_backup.FreeBlocks[1] = u8(freespace1);
// ... and update counter
int updateCtr = BE16(dir.UpdateCounter)+1;
dir.UpdateCounter[0] = u8(updateCtr>>8);
dir.UpdateCounter[1] = u8(updateCtr);
//fix checksums if (!remove)
u16 csum1=0,csum2=0; { // ... and dir update counter
calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); int updateCtr = BE16(dir_backup.UpdateCounter) + 1;
dir.CheckSum1[0]=u8(csum1>>8); dir_backup.UpdateCounter[0] = u8(updateCtr>>8);
dir.CheckSum1[1]=u8(csum1); dir_backup.UpdateCounter[1] = u8(updateCtr);
dir.CheckSum2[0]=u8(csum2>>8); // ... and bat update counter
dir.CheckSum2[1]=u8(csum2); updateCtr = BE16(bat_backup.UpdateCounter) + 1;
calc_checksumsBE((u16*)(((u8*)&bat)+4),0xFFE,&csum1,&csum2); bat_backup.UpdateCounter[0] = u8(updateCtr>>8);
bat.CheckSum1[0]=u8(csum1>>8); bat_backup.UpdateCounter[1] = u8(updateCtr);
bat.CheckSum1[1]=u8(csum1); }
bat.CheckSum2[0]=u8(csum2>>8); bat = bat_backup;
bat.CheckSum2[1]=u8(csum2);
if (!remove)
{
FixChecksums();
Save();
}
return fileBlocks; return fileBlocks;
} }
bool GCMemcard::GetFileData(u32 index, u8*dest) //index in the directory array bool GCMemcard::GetFileData(u32 index, u8*dest, bool old) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
int block = BE16(dir.Dir[index].FirstBlock); if (!old)
int saveLength = BE16(dir.Dir[index].BlockCount);
int memcardSize = BE16(hdr.Size) * 0x0010;
assert((block!=0xFFFF)&&(block>0));
do
{ {
memcpy(dest,mc_data + 0x2000*(block-5),0x2000); int block = BE16(dir.Dir[index].FirstBlock);
dest+=0x2000; int saveLength = BE16(dir.Dir[index].BlockCount) * 2000;
memcpy(dest,mc_data + 0x2000*(block-5), saveLength);
int nextblock = bswap16(bat.Map[block-5]);
if(block + saveLength != memcardSize && nextblock > 0)
{ //Fixes for older memcards that were not initialized with FF
block = nextblock;
}
else block = 0xffff;
} }
while(block!=0xffff); else
{
int block = BE16(dir.Dir[index].FirstBlock);
int saveLength = BE16(dir.Dir[index].BlockCount);
int memcardSize = BE16(hdr.Size) * 0x0010;
assert(block != 0xFFFF);
assert(block > 0);
do
{
memcpy(dest,mc_data + 0x2000 * (block - 5), 0x2000);
dest+=0x2000;
int nextblock = bswap16(bat.Map[block - 5]);
if(block + saveLength != memcardSize && nextblock > 0)
{ //Fixes for older memcards that were not initialized with FF
block = nextblock;
}
else block = 0xffff;
}
while (block != 0xffff);
}
return true; return true;
} }
u32 GCMemcard::GetFileSize(u32 index) //index in the directory array u32 GCMemcard::GetFileSize(u32 index) //index in the directory array
{ {
if(!mcdFile) return 0; if (!mcdFile) return 0;
return BE16(dir.Dir[index].BlockCount); return BE16(dir.Dir[index].BlockCount);
} }
bool GCMemcard::GetFileInfo(u32 index, GCMemcard::DEntry& info) //index in the directory array bool GCMemcard::GetFileInfo(u32 index, GCMemcard::DEntry& info) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
info = dir.Dir[index]; info = dir.Dir[index];
return true; return true;
} }
bool GCMemcard::GetFileName(u32 index, char *fn) //index in the directory array bool GCMemcard::GetFileName(u32 index, char *fn) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
memcpy(fn,(const char*)dir.Dir[index].Filename,32); memcpy (fn, (const char*)dir.Dir[index].Filename, 32);
fn[31]=0; fn[31] = 0;
return true; return true;
} }
bool GCMemcard::GetComment1(u32 index, char *fn) //index in the directory array bool GCMemcard::GetComment1(u32 index, char *fn) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
u32 Comment1 =BE32(dir.Dir[index].CommentsAddr); u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
if(Comment1==0xFFFFFFFF) if (Comment1 == 0xFFFFFFFF)
{ {
fn[0]=0; fn[0] = 0;
return false; return false;
} }
memcpy(fn, mc_data + (DataBlock * 0x2000) + Comment1, 32);
memcpy(fn,mc_data +(DataBlock*0x2000) + Comment1,32); fn[31] = 0;
fn[31]=0;
return true; return true;
} }
bool GCMemcard::GetComment2(u32 index, char *fn) //index in the directory array bool GCMemcard::GetComment2(u32 index, char *fn) //index in the directory array
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
u32 Comment1 =BE32(dir.Dir[index].CommentsAddr); u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
u32 Comment2 =Comment1+32; u32 Comment2 = Comment1 + 32;
u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
if(Comment1==0xFFFFFFFF) if (Comment1 == 0xFFFFFFFF)
{ {
fn[0]=0; fn[0] = 0;
return false; return false;
} }
memcpy(fn, mc_data + (DataBlock * 0x2000) + Comment2, 32);
memcpy(fn,mc_data +(DataBlock*0x2000) + Comment2,32); fn[31] = 0;
fn[31]=0;
return true; return true;
} }
@ -435,70 +403,70 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height)
bool GCMemcard::ReadBannerRGBA8(u32 index, u32* buffer) bool GCMemcard::ReadBannerRGBA8(u32 index, u32* buffer)
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
int flags = dir.Dir[index].BIFlags; int flags = dir.Dir[index].BIFlags;
int bnrFormat = (flags&3); int bnrFormat = (flags&3);
if(bnrFormat==0) if (bnrFormat == 0)
return false; return false;
u32 DataOffset=BE32(dir.Dir[index].ImageOffset); u32 DataOffset = BE32(dir.Dir[index].ImageOffset);
u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
if(DataOffset==0xFFFFFFFF) if (DataOffset == 0xFFFFFFFF)
{ {
return false; return false;
} }
const int pixels = 96*32; const int pixels = 96*32;
if(bnrFormat&1) if (bnrFormat&1)
{ {
u8 *pxdata = (u8* )(mc_data +(DataBlock*0x2000) + DataOffset); u8 *pxdata = (u8* )(mc_data +(DataBlock*0x2000) + DataOffset);
u16 *paldata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset + pixels); u16 *paldata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset + pixels);
decodeCI8image(buffer,pxdata,paldata,96,32); decodeCI8image(buffer, pxdata, paldata, 96, 32);
} }
else else
{ {
u16 *pxdata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset); u16 *pxdata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset);
decode5A3image(buffer,pxdata,96,32); decode5A3image(buffer, pxdata, 96, 32);
} }
return true; return true;
} }
u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays)
{ {
if(!mcdFile) return 0; if (!mcdFile) return 0;
int formats = BE16(dir.Dir[index].IconFmt); int formats = BE16(dir.Dir[index].IconFmt);
int fdelays = BE16(dir.Dir[index].AnimSpeed); int fdelays = BE16(dir.Dir[index].AnimSpeed);
int flags = dir.Dir[index].BIFlags; int flags = dir.Dir[index].BIFlags;
int bnrFormat = (flags&3); int bnrFormat = (flags&3);
u32 DataOffset=BE32(dir.Dir[index].ImageOffset); u32 DataOffset = BE32(dir.Dir[index].ImageOffset);
u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5;
if(DataOffset==0xFFFFFFFF) if (DataOffset == 0xFFFFFFFF)
{ {
return 0; return 0;
} }
u8* animData=(u8*)(mc_data +(DataBlock*0x2000) + DataOffset); u8* animData = (u8*)(mc_data +(DataBlock*0x2000) + DataOffset);
switch(bnrFormat) switch (bnrFormat)
{ {
case 1: case 1:
case 3: case 3:
animData+=96*32 + 2*256; // image+palette animData += 96*32 + 2*256; // image+palette
break; break;
case 2: case 2:
animData+=96*32*2; animData += 96*32*2;
break; break;
} }
@ -507,24 +475,24 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays)
int frames = 0; int frames = 0;
for(int i=0;i<8;i++) for (int i = 0; i < 8; i++)
{ {
fmts[i] = (formats>>(2*i))&3; fmts[i] = (formats >> (2*i))&3;
delays[i] = ((fdelays>>(2*i))&3)<<2; delays[i] = ((fdelays >> (2*i))&3) << 2;
data[i] = animData; data[i] = animData;
switch(fmts[i]) switch (fmts[i])
{ {
case 1: // CI8 with shared palette case 1: // CI8 with shared palette
animData+=32*32; animData += 32*32;
frames++; frames++;
break; break;
case 2: // RGB5A3 case 2: // RGB5A3
animData+=32*32*2; animData += 32*32*2;
frames++; frames++;
break; break;
case 3: // CI8 with own palette case 3: // CI8 with own palette
animData+=32*32 + 2*256; animData += 32*32 + 2*256;
frames++; frames++;
break; break;
} }
@ -532,21 +500,21 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays)
u16* sharedPal = (u16*)(animData); u16* sharedPal = (u16*)(animData);
for(int i=0;i<8;i++) for (int i = 0; i < 8; i++)
{ {
switch(fmts[i]) switch (fmts[i])
{ {
case 1: // CI8 with shared palette case 1: // CI8 with shared palette
decodeCI8image(buffer,data[i],sharedPal,32,32); decodeCI8image(buffer,data[i],sharedPal,32,32);
buffer+=32*32; buffer += 32*32;
break; break;
case 2: // RGB5A3 case 2: // RGB5A3
decode5A3image(buffer,(u16*)(data[i]),32,32); decode5A3image(buffer, (u16*)(data[i]), 32, 32);
break; break;
case 3: // CI8 with own palette case 3: // CI8 with own palette
u16 *paldata = (u16*)(data[i]+32*32); u16 *paldata = (u16*)(data[i] + 32*32);
decodeCI8image(buffer,data[i],paldata,32,32); decodeCI8image(buffer, data[i], paldata, 32, 32);
buffer+=32*32; buffer += 32*32;
break; break;
} }
} }
@ -556,94 +524,95 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays)
u32 GCMemcard::TestChecksums() u32 GCMemcard::TestChecksums()
{ {
if(!mcdFile) return 0xFFFFFFFF; if (!mcdFile) return 0xFFFFFFFF;
u16 csum1=0,csum2=0; u16 csum1=0,
csum2=0;
u32 results = 0; u32 results = 0;
calc_checksumsBE((u16*)&hdr, 0xFE ,&csum1,&csum2); calc_checksumsBE((u16*)&hdr, 0xFE , &csum1, &csum2);
if(BE16(hdr.CheckSum1)!=csum1) results |= 1; if (BE16(hdr.CheckSum1) != csum1) results |= 1;
if(BE16(hdr.CheckSum2)!=csum2) results |= 1; if (BE16(hdr.CheckSum2) != csum2) results |= 1;
calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
if(BE16(dir.CheckSum1)!=csum1) results |= 2; if (BE16(dir.CheckSum1) != csum1) results |= 2;
if(BE16(dir.CheckSum2)!=csum2) results |= 2; if (BE16(dir.CheckSum2) != csum2) results |= 2;
calc_checksumsBE((u16*)&dir_backup,0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
if(BE16(dir_backup.CheckSum1)!=csum1) results |= 4; if (BE16(dir_backup.CheckSum1) != csum1) results |= 4;
if(BE16(dir_backup.CheckSum2)!=csum2) 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, &csum1, &csum2);
if(BE16(bat.CheckSum1)!=csum1) results |= 8; if (BE16(bat.CheckSum1) != csum1) results |= 8;
if(BE16(bat.CheckSum2)!=csum2) 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, &csum1, &csum2);
if(BE16(bat_backup.CheckSum1)!=csum1) results |= 16; if (BE16(bat_backup.CheckSum1) != csum1) results |= 16;
if(BE16(bat_backup.CheckSum2)!=csum2) results |= 16; if (BE16(bat_backup.CheckSum2) != csum2) results |= 16;
return 0; return 0;
} }
bool GCMemcard::FixChecksums() bool GCMemcard::FixChecksums()
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
u16 csum1=0,csum2=0; u16 csum1=0,
csum2=0;
calc_checksumsBE((u16*)&hdr,0xFE,&csum1,&csum2); calc_checksumsBE((u16*)&hdr, 0xFE, &csum1, &csum2);
hdr.CheckSum1[0]=u8(csum1>>8); hdr.CheckSum1[0] = u8(csum1 >> 8);
hdr.CheckSum1[1]=u8(csum1); hdr.CheckSum1[1] = u8(csum1);
hdr.CheckSum2[0]=u8(csum2>>8); hdr.CheckSum2[0] = u8(csum2 >> 8);
hdr.CheckSum2[1]=u8(csum2); hdr.CheckSum2[1] = u8(csum2);
calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
dir.CheckSum1[0]=u8(csum1>>8); dir.CheckSum1[0] = u8(csum1 >> 8);
dir.CheckSum1[1]=u8(csum1); dir.CheckSum1[1] = u8(csum1);
dir.CheckSum2[0]=u8(csum2>>8); dir.CheckSum2[0] = u8(csum2 >> 8);
dir.CheckSum2[1]=u8(csum2); dir.CheckSum2[1] = u8(csum2);
calc_checksumsBE((u16*)&dir_backup,0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
dir_backup.CheckSum1[0]=u8(csum1>>8); dir_backup.CheckSum1[0] = u8(csum1 >> 8);
dir_backup.CheckSum1[1]=u8(csum1); dir_backup.CheckSum1[1] = u8(csum1);
dir_backup.CheckSum2[0]=u8(csum2>>8); dir_backup.CheckSum2[0] = u8(csum2 >> 8);
dir_backup.CheckSum2[1]=u8(csum2); dir_backup.CheckSum2[1] = u8(csum2);
calc_checksumsBE((u16*)(((u8*)&bat)+4),0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2);
bat.CheckSum1[0]=u8(csum1>>8); bat.CheckSum1[0] = u8(csum1 >> 8);
bat.CheckSum1[1]=u8(csum1); bat.CheckSum1[1] = u8(csum1);
bat.CheckSum2[0]=u8(csum2>>8); bat.CheckSum2[0] = u8(csum2 >> 8);
bat.CheckSum2[1]=u8(csum2); bat.CheckSum2[1] = u8(csum2);
calc_checksumsBE((u16*)(((u8*)&bat_backup)+4),0xFFE,&csum1,&csum2); calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2);
bat_backup.CheckSum1[0]=u8(csum1>>8); bat_backup.CheckSum1[0] = u8(csum1 >> 8);
bat_backup.CheckSum1[1]=u8(csum1); bat_backup.CheckSum1[1] = u8(csum1);
bat_backup.CheckSum2[0]=u8(csum2>>8); bat_backup.CheckSum2[0] = u8(csum2 >> 8);
bat_backup.CheckSum2[1]=u8(csum2); bat_backup.CheckSum2[1] = u8(csum2);
return true; return true;
} }
u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index)
{ {
if(!mcdFile) return 0; if (!mcdFile) return 0;
DEntry d; DEntry d;
if(!source.GetFileInfo(index,d)) return 0; if (!source.GetFileInfo(index, d)) return 0;
u8 *t = new u8[source.GetFileSize(index)*0x2000]; u8 *t = new u8[source.GetFileSize(index) * 0x2000];
if(!source.GetFileData(index,t)) return 0; if(!source.GetFileData(index, t, true)) return 0;
u32 ret = ImportFile(d,t); u32 ret = ImportFile(d,t,0);
delete[] t; delete[] t;
return ret; return ret;
} }
int GCMemcard::ImportGci(const char *fileName, const char *fileName2) s32 GCMemcard::ImportGci(const char *fileName, std::string fileName2)
{ {
if (!mcdFile && !fileName2) return OPENFAIL; if (fileName2.empty() && !mcdFile) return OPENFAIL;
FILE *gci = fopen(fileName, "rb"); FILE *gci = fopen(fileName, "rb");
if (!gci) return OPENFAIL; if (!gci) return OPENFAIL;
@ -653,7 +622,7 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2)
std::string fileType; std::string fileType;
SplitPath(fileName, NULL, NULL, &fileType); SplitPath(fileName, NULL, NULL, &fileType);
if( !strcasecmp(fileType.c_str(), ".gci") && !fileName2) if( !strcasecmp(fileType.c_str(), ".gci"))
offset = GCI; offset = GCI;
else else
{ {
@ -687,9 +656,9 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2)
DEntry *d = new DEntry; DEntry *d = new DEntry;
fread(d, 1, 0x40, gci); fread(d, 1, 0x40, gci);
int fStart = ftell(gci); int fStart = (int) ftell(gci);
fseek(gci, 0, SEEK_END); fseek(gci, 0, SEEK_END);
int length = ftell(gci) - fStart; int length = (int) ftell(gci) - fStart;
fseek(gci, offset + 0x40, SEEK_SET); fseek(gci, offset + 0x40, SEEK_SET);
switch(offset){ switch(offset){
@ -723,11 +692,11 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2)
default: default:
break; break;
} }
if (length == BE16(d->BlockCount) * 0x2000) if (length != BE16(d->BlockCount) * 0x2000)
{ {
return LENGTHFAIL; return LENGTHFAIL;
} }
if (ftell(gci) == offset + 0x40) // Verify correct file position if (ftell(gci) != offset + 0x40) // Verify correct file position
{ {
return OPENFAIL; return OPENFAIL;
} }
@ -735,21 +704,22 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2)
u8 *t = new u8[size]; u8 *t = new u8[size];
fread(t, 1, size, gci); fread(t, 1, size, gci);
fclose(gci); fclose(gci);
u32 ret = 0; u32 ret;
if(fileName2) if(!fileName2.empty())
{ {
FILE * gci2 = fopen(fileName2, "wb"); FILE * gci2 = fopen(fileName2.c_str(), "wb");
if (!gci2) return OPENFAIL; if (!gci2) return OPENFAIL;
fseek(gci2, 0, SEEK_SET); fseek(gci2, 0, SEEK_SET);
fwrite(d, 1, 0x40, gci2); assert(fwrite(d, 1, 0x40, gci2)==0x40);
int fileBlocks = BE16(d->BlockCount); int fileBlocks = BE16(d->BlockCount);
fseek(gci2, 0x40, SEEK_SET); fseek(gci2, 0x40, SEEK_SET);
fwrite(t, 0, 0x2000 * fileBlocks, gci2);
assert(fwrite(t, 1, 0x2000 * fileBlocks, gci2)==(unsigned) (0x2000*fileBlocks));
fclose(gci2); fclose(gci2);
ret = GCS;
} }
else ret = ImportFile(*d, t); else ret= ImportFile(*d, t,0);
delete []t; delete []t;
delete []tmp; delete []tmp;
delete d; delete d;
@ -759,18 +729,18 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2)
bool GCMemcard::ExportGci(u32 index, const char *fileName) bool GCMemcard::ExportGci(u32 index, const char *fileName)
{ {
FILE *gci = fopen(fileName, "wb"); FILE *gci = fopen(fileName, "wb");
if(!gci) return false; if (!gci) return false;
fseek(gci, 0, SEEK_SET); fseek(gci, 0, SEEK_SET);
DEntry d; DEntry d;
if(!this->GetFileInfo(index, d)) return false; if (!this->GetFileInfo(index, d)) return false;
fwrite(&d, 1, 0x40, gci); assert(fwrite(&d, 1, 0x40, gci) == 0x40);
u8 *t = new u8[this->GetFileSize(index) * 0x2000]; u8 *t = new u8[this->GetFileSize(index) * 0x2000];
if (!this->GetFileData(index, t)) return false; if (!this->GetFileData(index, t, true)) return false;
fseek(gci, 0x40, SEEK_SET); fseek(gci, 0x40, SEEK_SET);
fwrite(t, 1, 0x2000 * BE16(d.BlockCount), gci); assert(fwrite(t, 1, 0x2000 * BE16(d.BlockCount), gci)== (unsigned) (0x2000 * BE16(d.BlockCount)));
fclose(gci); fclose(gci);
delete []t; delete []t;
return true; return true;
@ -778,16 +748,16 @@ bool GCMemcard::ExportGci(u32 index, const char *fileName)
bool GCMemcard::Save() bool GCMemcard::Save()
{ {
if(!mcdFile) return false; if (!mcdFile) return false;
FILE *mcd=(FILE*)mcdFile; FILE *mcd=(FILE*)mcdFile;
fseek(mcd,0,SEEK_SET); fseek(mcd, 0, SEEK_SET);
fwrite(&hdr,1,0x2000,mcd); assert(fwrite(&hdr, 1, 0x2000, mcd) == 0x2000);
fwrite(&dir,1,0x2000,mcd); assert(fwrite(&dir, 1, 0x2000, mcd) == 0x2000);
fwrite(&dir_backup,1,0x2000,mcd); assert(fwrite(&dir_backup, 1, 0x2000, mcd) == 0x2000);
fwrite(&bat,1,0x2000,mcd); assert(fwrite(&bat, 1, 0x2000 ,mcd) == 0x2000);
fwrite(&bat_backup,1,0x2000,mcd); assert(fwrite(&bat_backup, 1, 0x2000, mcd) == 0x2000);
fwrite(mc_data,1,mc_data_size,mcd); assert(fwrite(mc_data, 1, mc_data_size, mcd) == mc_data_size);
return true; return true;
} }
@ -798,28 +768,28 @@ bool GCMemcard::IsOpen()
GCMemcard::GCMemcard(const char *filename) GCMemcard::GCMemcard(const char *filename)
{ {
FILE *mcd=fopen(filename,"r+b"); FILE *mcd = fopen(filename,"r+b");
mcdFile=mcd; mcdFile = mcd;
if(!mcd) return; if (!mcd) return;
fseek(mcd,0x0000,SEEK_SET); fseek(mcd, 0x0000, SEEK_SET);
assert(fread(&hdr, 1,0x2000,mcd)==0x2000); assert(fread(&hdr, 1, 0x2000, mcd) == 0x2000);
assert(fread(&dir, 1,0x2000,mcd)==0x2000); assert(fread(&dir, 1, 0x2000, mcd) == 0x2000);
assert(fread(&dir_backup,1,0x2000,mcd)==0x2000); assert(fread(&dir_backup, 1, 0x2000, mcd) == 0x2000);
assert(fread(&bat, 1,0x2000,mcd)==0x2000); assert(fread(&bat, 1, 0x2000, mcd) == 0x2000);
assert(fread(&bat_backup,1,0x2000,mcd)==0x2000); assert(fread(&bat_backup, 1, 0x2000, mcd) == 0x2000);
u32 csums = TestChecksums(); u32 csums = TestChecksums();
if(csums&1) if (csums&1)
{ {
// header checksum error! // header checksum error!
// TODO: fail to load // TODO: fail to load
} }
if(csums&2) // directory checksum error! if (csums&2) // directory checksum error!
{ {
if(csums&4) if (csums&4)
{ {
// backup is also wrong! // backup is also wrong!
// TODO: fail to load // TODO: fail to load
@ -835,9 +805,9 @@ GCMemcard::GCMemcard(const char *filename)
} }
} }
if(csums&8) // BAT checksum error! if (csums&8) // BAT checksum error!
{ {
if(csums&16) if (csums&16)
{ {
// backup is also wrong! // backup is also wrong!
// TODO: fail to load // TODO: fail to load
@ -861,23 +831,17 @@ GCMemcard::GCMemcard(const char *filename)
// bat = bat_backup; // needed? // bat = bat_backup; // needed?
} }
fseek(mcd,0xa000,SEEK_SET); fseek(mcd, 0xa000, SEEK_SET);
assert(BE16(hdr.Size)!=0xFFFF); assert(BE16(hdr.Size) != 0xFFFF);
mc_data_size=(((u32)BE16(hdr.Size)*16)-5)*0x2000; mc_data_size = (((u32)BE16(hdr.Size) * 16) - 5) * 0x2000;
mc_data = new u8[mc_data_size]; mc_data = new u8[mc_data_size];
size_t read = fread(mc_data,1,mc_data_size,mcd); size_t read = fread(mc_data, 1, mc_data_size, mcd);
assert(mc_data_size==read); assert(mc_data_size == read);
} }
GCMemcard::~GCMemcard() GCMemcard::~GCMemcard()
{ {
fclose((FILE*)mcdFile); fclose((FILE*)mcdFile);
} }
void varSwap(u8 *valueA,u8 *valueB){
u8 temp = *valueA;
*valueA = *valueB;
*valueB = temp;
}

View File

@ -28,7 +28,10 @@ enum
OPENFAIL, OPENFAIL,
GCI, GCI,
SAV = 0x80, SAV = 0x80,
GCS = 0x110 GCS = 0x110,
OUTOFBLOCKS,
OUTOFDIRENTRIES,
NOMEMCARD
}; };
class GCMemcard class GCMemcard
@ -155,13 +158,17 @@ public:
u32 GetFileSize(u32 index); u32 GetFileSize(u32 index);
// assumes there's enough space in buffer // assumes there's enough space in buffer
bool GetFileData(u32 index, u8* buffer); // 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
// TODO: find a function that works for all calls or split into 2 functions
bool GetFileData(u32 index, u8* buffer, bool old);
// delete a file from the directory // delete a file from the directory
bool RemoveFile(u32 index); bool RemoveFile(u32 index);
// adds the file to the directory and copies its contents // adds the file to the directory and copies its contents
u32 ImportFile(DEntry& direntry, u8* contents); // if remove > 0 it will pad bat.map with 0's sifeof remove
u32 ImportFile(DEntry& direntry, u8* contents, int remove);
// reads a save from another memcard, and imports the data into this memcard // reads a save from another memcard, and imports the data into this memcard
u32 CopyFrom(GCMemcard& source, u32 index); u32 CopyFrom(GCMemcard& source, u32 index);
@ -170,7 +177,7 @@ public:
bool ExportGci(u32 index, const char* fileName); bool ExportGci(u32 index, const char* fileName);
// reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file
int ImportGci(const char* fileName, const char* fileName2); s32 ImportGci(const char* fileName, std::string fileName2);
// reads the banner image // reads the banner image
bool ReadBannerRGBA8(u32 index, u32* buffer); bool ReadBannerRGBA8(u32 index, u32* buffer);