diff --git a/Source/Core/DolphinWX/src/MemcardManager.cpp b/Source/Core/DolphinWX/src/MemcardManager.cpp index 66cb0b2733..94712114b9 100644 --- a/Source/Core/DolphinWX/src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/src/MemcardManager.cpp @@ -32,11 +32,15 @@ END_EVENT_TABLE() CMemcardManager::CMemcardManager(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) : wxDialog(parent, id, title, position, size, style) { + memoryCard[0]=NULL; + memoryCard[1]=NULL; CreateGUIControls(); } CMemcardManager::~CMemcardManager() { + if(memoryCard[0]) delete memoryCard[0]; + if(memoryCard[1]) delete memoryCard[1]; } void CMemcardManager::CreateGUIControls() @@ -135,7 +139,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) case ID_DELETERIGHT: if(index1 != -1) { - memoryCard[1]->DeleteFile(index1); + memoryCard[1]->RemoveFile(index1); memoryCard[1]->Save(); ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1); } @@ -143,7 +147,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) case ID_DELETELEFT: if(index0 != -1) { - memoryCard[0]->DeleteFile(index0); + memoryCard[0]->RemoveFile(index0); memoryCard[0]->Save(); ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); } @@ -153,6 +157,8 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) void CMemcardManager::ReloadMemcard(const char *fileName, int card) { + if(memoryCard[card]) delete memoryCard[card]; + // TODO: add error checking and banners/icons memoryCard[card] = new GCMemcard(fileName); diff --git a/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.cpp b/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.cpp index 877fe8e522..2baac40844 100644 --- a/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.cpp +++ b/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.cpp @@ -32,7 +32,7 @@ u32 GCMemcard::GetNumFiles() { if(!mcdFile) return 0; - for(int i=0;i<127;i++) + for(int i=0;i<126;i++) { if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF) return i; @@ -40,7 +40,7 @@ u32 GCMemcard::GetNumFiles() return 127; } -bool GCMemcard::DeleteFile(u32 index) //index in the directory array +bool GCMemcard::RemoveFile(u32 index) //index in the directory array { if(!mcdFile) return false; @@ -71,17 +71,17 @@ bool GCMemcard::DeleteFile(u32 index) //index in the directory array while((block!=0xffff)&&(blocks_left>0)); //delete directory entry - for(int i=index;i<126;i++) + for(int i=index;i<125;i++) { dir.Dir[i]=dir.Dir[i+1]; } - memset(&(dir.Dir[126]),0xFF,sizeof(DEntry)); + 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<127;i++) + for(int i=0;i<126;i++) { if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF) { @@ -102,8 +102,8 @@ bool GCMemcard::DeleteFile(u32 index) //index in the directory array } bat.Map[firstFree+bc-1] = 0xFFFF; - dir.Dir[i].FirstBlock[0] = u8(firstFree>>8); - dir.Dir[i].FirstBlock[1] = u8(firstFree); + dir.Dir[i].FirstBlock[0] = u8((firstFree+5)>>8); + dir.Dir[i].FirstBlock[1] = u8((firstFree+5)); firstFree += bc; } @@ -126,6 +126,11 @@ bool GCMemcard::DeleteFile(u32 index) //index in the directory array 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); + //fix checksums u16 csum1=0,csum2=0; calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); @@ -139,6 +144,9 @@ bool GCMemcard::DeleteFile(u32 index) //index in the directory array bat.CheckSum2[0]=u8(csum2>>8); bat.CheckSum2[1]=u8(csum2); + dir_backup=dir; + bat_backup=bat; + return true; } @@ -167,7 +175,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents) } int firstFree3 = 0; - for(int i=0;i<127;i++) + for(int i=0;i<126;i++) { if(BE32(dir.Dir[i].Gamecode)==0xFFFFFFFF) { @@ -182,6 +190,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents) if(firstFree2 > firstFree1) firstFree1 = firstFree2; if(firstFree3 > firstFree1) firstFree1 = firstFree3; + if(firstFree1>=126) + { + // TODO: show messagebox about the error + return 0; + } + // find first free dir entry int index=-1; for(int i=0;i<127;i++) @@ -192,6 +206,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents) dir.Dir[i] = direntry; dir.Dir[i].FirstBlock[0] = u8(firstFree1>>8); dir.Dir[i].FirstBlock[1] = u8(firstFree1); + dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; break; } } @@ -208,6 +223,11 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents) 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); + //fix checksums u16 csum1=0,csum2=0; calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); @@ -309,25 +329,27 @@ u32 GCMemcard::TestChecksums() u16 csum1=0,csum2=0; + u32 results = 0; + calc_checksumsBE((u16*)&hdr, 0xFE ,&csum1,&csum2); - if(BE16(hdr.CheckSum1)!=csum1) return 1; - if(BE16(hdr.CheckSum2)!=csum2) return 1; + if(BE16(hdr.CheckSum1)!=csum1) results |= 1; + if(BE16(hdr.CheckSum2)!=csum2) results |= 1; calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); - if(BE16(dir.CheckSum1)!=csum1) return 2; - if(BE16(dir.CheckSum2)!=csum2) return 2; + if(BE16(dir.CheckSum1)!=csum1) results |= 2; + if(BE16(dir.CheckSum2)!=csum2) results |= 2; calc_checksumsBE((u16*)&dir_backup,0xFFE,&csum1,&csum2); - if(BE16(dir_backup.CheckSum1)!=csum1) return 3; - if(BE16(dir_backup.CheckSum2)!=csum2) return 3; + if(BE16(dir_backup.CheckSum1)!=csum1) results |= 4; + if(BE16(dir_backup.CheckSum2)!=csum2) results |= 4; calc_checksumsBE((u16*)(((u8*)&bat)+4),0xFFE,&csum1,&csum2); - if(BE16(bat.CheckSum1)!=csum1) return 4; - if(BE16(bat.CheckSum2)!=csum2) return 4; + if(BE16(bat.CheckSum1)!=csum1) results |= 8; + if(BE16(bat.CheckSum2)!=csum2) results |= 8; calc_checksumsBE((u16*)(((u8*)&bat_backup)+4),0xFFE,&csum1,&csum2); - if(BE16(bat_backup.CheckSum1)!=csum1) return 5; - if(BE16(bat_backup.CheckSum2)!=csum2) return 5; + if(BE16(bat_backup.CheckSum1)!=csum1) results |= 16; + if(BE16(bat_backup.CheckSum2)!=csum2) results |= 16; return 0; } @@ -382,6 +404,56 @@ GCMemcard::GCMemcard(const char *filename) assert(fread(&bat, 1,0x2000,mcd)==0x2000); assert(fread(&bat_backup,1,0x2000,mcd)==0x2000); + u32 csums = TestChecksums(); + + if(csums&1) + { + // header checksum error! + // TODO: fail to load + } + + if(csums&2) // directory checksum error! + { + if(csums&4) + { + // backup is also wrong! + // TODO: fail to load + } + else + { + // backup is correct, restore + dir = dir_backup; + bat = bat_backup; + + // update checksums + csums = TestChecksums(); + } + } + + if(csums&8) // BAT checksum error! + { + if(csums&16) + { + // backup is also wrong! + // TODO: fail to load + } + else + { + // backup is correct, restore + dir = dir_backup; + bat = bat_backup; + + // update checksums + csums = TestChecksums(); + } + } + + if(BE16(dir_backup.UpdateCounter) > BE16(dir.UpdateCounter)) //check if the backup is newer + { + dir = dir_backup; + bat = bat_backup; // needed? + } + fseek(mcd,0xa000,SEEK_SET); mc_data_size=(((u32)BE16(hdr.Size)*16)-5)*0x2000; diff --git a/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.h b/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.h index 94cfe96b34..c9ae243a61 100644 --- a/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.h +++ b/Source/Core/DolphinWX/src/MemoryCards/GCMemcard.h @@ -146,7 +146,7 @@ public: bool GetFileData(u32 index, u8* buffer); // delete a file from the directory - bool DeleteFile(u32 index); + bool RemoveFile(u32 index); // adds the file to the directory and copies its contents u32 ImportFile(DEntry& direntry, u8* contents); diff --git a/Source/Dolphin.sln b/Source/Dolphin.sln index 736757d61a..bd7c3b8524 100644 --- a/Source/Dolphin.sln +++ b/Source/Dolphin.sln @@ -277,8 +277,8 @@ Global {805B34AA-82A5-4875-8DC7-3C85BDC0BCEE}.Release|x64.Build.0 = Release|x64 {521498BE-6089-4780-8223-E67C22F4E068}.Debug|Win32.ActiveCfg = Debug|Win32 {521498BE-6089-4780-8223-E67C22F4E068}.Debug|Win32.Build.0 = Debug|Win32 - {521498BE-6089-4780-8223-E67C22F4E068}.Debug|x64.ActiveCfg = Debug|x64 - {521498BE-6089-4780-8223-E67C22F4E068}.Debug|x64.Build.0 = Debug|x64 + {521498BE-6089-4780-8223-E67C22F4E068}.Debug|x64.ActiveCfg = Release|x64 + {521498BE-6089-4780-8223-E67C22F4E068}.Debug|x64.Build.0 = Release|x64 {521498BE-6089-4780-8223-E67C22F4E068}.DebugFast|Win32.ActiveCfg = DebugFast|Win32 {521498BE-6089-4780-8223-E67C22F4E068}.DebugFast|Win32.Build.0 = DebugFast|Win32 {521498BE-6089-4780-8223-E67C22F4E068}.DebugFast|x64.ActiveCfg = DebugFast|x64