diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index c27a5c0a4b..10535180ff 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -72,8 +72,8 @@ wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, int width, int height BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) EVT_CLOSE(CMemcardManager::OnClose) - EVT_BUTTON(ID_COPYLEFT,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_COPYRIGHT,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_COPYTOLEFT,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_COPYTORIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_FIXCHECKSUM,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETELEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETERIGHT,CMemcardManager::CopyDeleteClick) @@ -111,8 +111,8 @@ CMemcardManager::~CMemcardManager() void CMemcardManager::CreateGUIControls() { // buttons - m_CopyLeft = new wxButton(this, ID_COPYLEFT, wxT("<-Copy<-"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); - m_CopyRight = new wxButton(this, ID_COPYRIGHT, wxT("->Copy->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_CopyToLeft = new wxButton(this, ID_COPYTOLEFT, 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); @@ -150,8 +150,8 @@ void CMemcardManager::CreateGUIControls() wxBoxSizer* sButtons; sButtons = new wxBoxSizer(wxVERTICAL); sButtons->AddStretchSpacer(2); - sButtons->Add(m_CopyLeft, 0, wxEXPAND, 5); - sButtons->Add(m_CopyRight, 0, wxEXPAND, 5); + sButtons->Add(m_CopyToLeft, 0, wxEXPAND, 5); + sButtons->Add(m_CopyToRight, 0, wxEXPAND, 5); sButtons->AddStretchSpacer(1); sButtons->Add(m_FixChecksum, 0, wxEXPAND, 5); 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 slot = 1; int index2 = index1; - char * fileName2 = NULL; + std::string fileName2(""); + int freeblocks = 0; - switch(event.GetId()) + switch (event.GetId()) { - case ID_COPYLEFT: - slot=0; - index2 = index0; - case ID_COPYRIGHT: - if ((index2 != -1) && (memoryCard[slot] != NULL)) + case ID_COPYTOLEFT: + if ((index1 != -1) && (memoryCard[0] != NULL)) { - int slot2; - slot == 0 ? slot2=1:slot2=0; - memoryCard[slot]->CopyFrom(*memoryCard[slot2], index2); - memoryCard[slot]->Save(); - slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) - : ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); + memoryCard[0]->CopyFrom(*memoryCard[1], index1); + memoryCard[0]->Save(); + ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); + } + break; + 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; case ID_FIXCHECKSUM: @@ -234,11 +237,12 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) } break; case ID_CONVERTTOGCI: - fileName2 = new char; + fileName2 = "convert"; + case ID_SAVEIMPORTLEFT: slot = 0; 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"), wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format @@ -249,10 +253,10 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) "Datel MaxDrive/Pro files(*.sav)|*.sav"), wxFileSelectorDefaultWildcardStr, wxFileSelectorDefaultWildcardStr - ), - wxFD_OPEN | wxFD_FILE_MUST_EXIST); + ), + wxFD_OPEN | wxFD_FILE_MUST_EXIST); const char * fileName = temp.ToAscii(); - if (*fileName2 != NULL && !temp.empty()) + if (!temp.empty() && !fileName2.empty()) { wxString temp2 = wxFileSelector(_T("Save GCI as.."), wxEmptyString, wxEmptyString, _T(".gci"), wxString::Format @@ -262,8 +266,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) wxFileSelectorDefaultWildcardStr ), wxFD_OVERWRITE_PROMPT|wxFD_SAVE); - delete fileName2; - fileName2 = (char*)temp2.ToAscii(); + fileName2 = temp2.mb_str(); } if (temp.length() > 0) { @@ -288,6 +291,26 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) " does not have a valid extension"), wxT("Error"), wxOK|wxICON_ERROR); 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: memoryCard[slot]->Save(); slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) diff --git a/Source/Core/DolphinWX/Src/MemcardManager.h b/Source/Core/DolphinWX/Src/MemcardManager.h index 9d6f146226..962b4f78cb 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.h +++ b/Source/Core/DolphinWX/Src/MemcardManager.h @@ -26,7 +26,7 @@ #include #include "MemoryCards/GCMemcard.h" - +#define BE16(x) ((u16((x)[0])<<8) | u16((x)[1])) #undef MEMCARD_MANAGER_STYLE #define MEMCARD_MANAGER_STYLE wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | wxMAXIMIZE_BOX @@ -35,7 +35,7 @@ class CMemcardManager { 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(); private: @@ -43,8 +43,8 @@ class CMemcardManager DECLARE_EVENT_TABLE(); wxBoxSizer *sMain; - wxButton *m_CopyLeft; - wxButton *m_CopyRight; + wxButton *m_CopyToLeft; + wxButton *m_CopyToRight; wxButton *m_FixChecksum; wxButton *m_SaveImportLeft; wxButton *m_SaveExportLeft; @@ -62,8 +62,8 @@ class CMemcardManager enum { - ID_COPYRIGHT = 1000, - ID_COPYLEFT, + ID_COPYTORIGHT = 1000, + ID_COPYTOLEFT, ID_FIXCHECKSUM, ID_DELETERIGHT, ID_DELETELEFT, diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp index f05ab0a9d7..645fe81fb1 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp @@ -20,7 +20,6 @@ #endif #include #include -#include "wx/ffile.h" #include "GCMemcard.h" @@ -74,11 +73,11 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2) u32 GCMemcard::GetNumFiles() { - if(!mcdFile) return 0; - int j =0; - for(int i=0;i<126;i++) + if (!mcdFile) return 0; + int j = 0; + for (int i = 0; i < 127; i++) { - if(BE32(dir.Dir[i].Gamecode)!=0xFFFFFFFF) + if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) j++; } return j; @@ -86,285 +85,254 @@ u32 GCMemcard::GetNumFiles() 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 - dir_backup=dir; - bat_backup=bat; - - int totalspace = (((u32)BE16(hdr.Size)*16)-5); + dir_backup = dir; + bat_backup = bat; //free the blocks int blocks_left = BE16(dir.Dir[index].BlockCount); 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; - int nextblock=bswap16(bat.Map[cbi]); - //assert(nextblock!=0); - if(nextblock==0) + DEntry * d = new DEntry; + GetFileInfo(i, *d); + u8 *t = NULL; + //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; + } } - - bat.Map[cbi]=0; - - 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) + memset(&(dir.Dir[i]), 0xFF, 0x40); + //Only call import file if Get File Data returns true + if (t) { - 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>8); - dir.Dir[i].FirstBlock[1] = u8((firstFree+5)); - - firstFree += bc; } - for(int j=firstFree;j>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); + // increment 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); - 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; + + FixChecksums(); + Save(); 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)= 127) { - return 0; + return OUTOFDIRENTRIES; + } + if (BE16(bat.FreeBlocks) < BE16(direntry.BlockCount)) + { + return OUTOFBLOCKS; } // find first free data block -- assume no freespace fragmentation - int totalspace = (((u32)BE16(hdr.Size)*16)-5); - - int firstFree1 = BE16(bat.LastAllocated)+1; + int totalspace = (((u32)BE16(hdr.Size) * 16) - 5); + int firstFree1 = BE16(bat.LastAllocated) + 1; int firstFree2 = 0; - for(int i=0;i(firstFree3,(int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount))); + firstFree2 = max(firstFree2, + (int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount))); } } - firstFree1 = max(firstFree1, max(firstFree3, firstFree2)); - if(firstFree1>=126) - { - // TODO: show messagebox about the error - return 0; - } + firstFree1 = max(firstFree1, firstFree2); // find first free dir entry - int index=-1; - for(int i=0;i<127;i++) + int index = -1; + 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].FirstBlock[0] = u8(firstFree1>>8); + dir.Dir[i].FirstBlock[0] = u8(firstFree1 >> 8); 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; } } // 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); - memcpy(destination,contents,0x2000*fileBlocks); + int fileBlocks = BE16(direntry.BlockCount); + 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 - int freespace1 = totalspace - firstFree1; - bat.FreeBlocks[0] = u8(freespace1>>8); - bat.FreeBlocks[1] = u8(freespace1); + int freespace1 = totalspace - firstFree1 - fileBlocks + 5; + bat_backup.FreeBlocks[0] = u8(freespace1 >> 8); + 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 - u16 csum1=0,csum2=0; - calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); - 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); + if (!remove) + { // ... and dir update counter + int updateCtr = BE16(dir_backup.UpdateCounter) + 1; + dir_backup.UpdateCounter[0] = u8(updateCtr>>8); + dir_backup.UpdateCounter[1] = u8(updateCtr); + // ... and bat update counter + updateCtr = BE16(bat_backup.UpdateCounter) + 1; + bat_backup.UpdateCounter[0] = u8(updateCtr>>8); + bat_backup.UpdateCounter[1] = u8(updateCtr); + } + bat = bat_backup; + if (!remove) + { + FixChecksums(); + Save(); + } 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); - int saveLength = BE16(dir.Dir[index].BlockCount); - int memcardSize = BE16(hdr.Size) * 0x0010; - assert((block!=0xFFFF)&&(block>0)); - do + if (!old) { - 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; + int block = BE16(dir.Dir[index].FirstBlock); + int saveLength = BE16(dir.Dir[index].BlockCount) * 2000; + memcpy(dest,mc_data + 0x2000*(block-5), saveLength); } - 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; } u32 GCMemcard::GetFileSize(u32 index) //index in the directory array { - if(!mcdFile) return 0; + if (!mcdFile) return 0; return BE16(dir.Dir[index].BlockCount); } 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]; return true; } 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); - fn[31]=0; + memcpy (fn, (const char*)dir.Dir[index].Filename, 32); + fn[31] = 0; return true; } 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 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; - if(Comment1==0xFFFFFFFF) + u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); + u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5; + if (Comment1 == 0xFFFFFFFF) { - fn[0]=0; + fn[0] = 0; return false; } - - memcpy(fn,mc_data +(DataBlock*0x2000) + Comment1,32); - fn[31]=0; + memcpy(fn, mc_data + (DataBlock * 0x2000) + Comment1, 32); + fn[31] = 0; return true; } 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 Comment2 =Comment1+32; - u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; - if(Comment1==0xFFFFFFFF) + u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); + u32 Comment2 = Comment1 + 32; + u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5; + if (Comment1 == 0xFFFFFFFF) { - fn[0]=0; + fn[0] = 0; return false; } - - memcpy(fn,mc_data +(DataBlock*0x2000) + Comment2,32); - fn[31]=0; + memcpy(fn, mc_data + (DataBlock * 0x2000) + Comment2, 32); + fn[31] = 0; 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) { - if(!mcdFile) return false; + if (!mcdFile) return false; int flags = dir.Dir[index].BIFlags; int bnrFormat = (flags&3); - if(bnrFormat==0) + if (bnrFormat == 0) return false; - u32 DataOffset=BE32(dir.Dir[index].ImageOffset); - u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; + u32 DataOffset = BE32(dir.Dir[index].ImageOffset); + u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5; - if(DataOffset==0xFFFFFFFF) + if (DataOffset == 0xFFFFFFFF) { return false; } const int pixels = 96*32; - if(bnrFormat&1) + if (bnrFormat&1) { u8 *pxdata = (u8* )(mc_data +(DataBlock*0x2000) + DataOffset); u16 *paldata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset + pixels); - decodeCI8image(buffer,pxdata,paldata,96,32); + decodeCI8image(buffer, pxdata, paldata, 96, 32); } else { u16 *pxdata = (u16*)(mc_data +(DataBlock*0x2000) + DataOffset); - decode5A3image(buffer,pxdata,96,32); + decode5A3image(buffer, pxdata, 96, 32); } return true; } 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 fdelays = BE16(dir.Dir[index].AnimSpeed); int flags = dir.Dir[index].BIFlags; - int bnrFormat = (flags&3); + int bnrFormat = (flags&3); - u32 DataOffset=BE32(dir.Dir[index].ImageOffset); - u32 DataBlock =BE16(dir.Dir[index].FirstBlock)-5; + u32 DataOffset = BE32(dir.Dir[index].ImageOffset); + u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - 5; - if(DataOffset==0xFFFFFFFF) + if (DataOffset == 0xFFFFFFFF) { 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 3: - animData+=96*32 + 2*256; // image+palette + animData += 96*32 + 2*256; // image+palette break; case 2: - animData+=96*32*2; + animData += 96*32*2; break; } @@ -507,24 +475,24 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) int frames = 0; - for(int i=0;i<8;i++) + for (int i = 0; i < 8; i++) { - fmts[i] = (formats>>(2*i))&3; - delays[i] = ((fdelays>>(2*i))&3)<<2; + fmts[i] = (formats >> (2*i))&3; + delays[i] = ((fdelays >> (2*i))&3) << 2; data[i] = animData; - switch(fmts[i]) + switch (fmts[i]) { case 1: // CI8 with shared palette - animData+=32*32; + animData += 32*32; frames++; break; case 2: // RGB5A3 - animData+=32*32*2; + animData += 32*32*2; frames++; break; case 3: // CI8 with own palette - animData+=32*32 + 2*256; + animData += 32*32 + 2*256; frames++; break; } @@ -532,21 +500,21 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) 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 decodeCI8image(buffer,data[i],sharedPal,32,32); - buffer+=32*32; + buffer += 32*32; break; case 2: // RGB5A3 - decode5A3image(buffer,(u16*)(data[i]),32,32); + decode5A3image(buffer, (u16*)(data[i]), 32, 32); break; case 3: // CI8 with own palette - u16 *paldata = (u16*)(data[i]+32*32); - decodeCI8image(buffer,data[i],paldata,32,32); - buffer+=32*32; + u16 *paldata = (u16*)(data[i] + 32*32); + decodeCI8image(buffer, data[i], paldata, 32, 32); + buffer += 32*32; break; } } @@ -556,94 +524,95 @@ u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) u32 GCMemcard::TestChecksums() { - if(!mcdFile) return 0xFFFFFFFF; + if (!mcdFile) return 0xFFFFFFFF; - u16 csum1=0,csum2=0; + u16 csum1=0, + csum2=0; u32 results = 0; - calc_checksumsBE((u16*)&hdr, 0xFE ,&csum1,&csum2); - if(BE16(hdr.CheckSum1)!=csum1) results |= 1; - if(BE16(hdr.CheckSum2)!=csum2) results |= 1; + calc_checksumsBE((u16*)&hdr, 0xFE , &csum1, &csum2); + 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) results |= 2; - if(BE16(dir.CheckSum2)!=csum2) results |= 2; + calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2); + 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) results |= 4; - if(BE16(dir_backup.CheckSum2)!=csum2) results |= 4; + calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2); + 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) results |= 8; - if(BE16(bat.CheckSum2)!=csum2) results |= 8; + calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2); + 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) results |= 16; - if(BE16(bat_backup.CheckSum2)!=csum2) results |= 16; + calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2); + if (BE16(bat_backup.CheckSum1) != csum1) results |= 16; + if (BE16(bat_backup.CheckSum2) != csum2) results |= 16; return 0; } 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); - hdr.CheckSum1[0]=u8(csum1>>8); - hdr.CheckSum1[1]=u8(csum1); - hdr.CheckSum2[0]=u8(csum2>>8); - hdr.CheckSum2[1]=u8(csum2); + calc_checksumsBE((u16*)&hdr, 0xFE, &csum1, &csum2); + hdr.CheckSum1[0] = u8(csum1 >> 8); + hdr.CheckSum1[1] = u8(csum1); + hdr.CheckSum2[0] = u8(csum2 >> 8); + hdr.CheckSum2[1] = u8(csum2); - calc_checksumsBE((u16*)&dir,0xFFE,&csum1,&csum2); - 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*)&dir, 0xFFE, &csum1, &csum2); + 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*)&dir_backup,0xFFE,&csum1,&csum2); - dir_backup.CheckSum1[0]=u8(csum1>>8); - dir_backup.CheckSum1[1]=u8(csum1); - dir_backup.CheckSum2[0]=u8(csum2>>8); - dir_backup.CheckSum2[1]=u8(csum2); + calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2); + dir_backup.CheckSum1[0] = u8(csum1 >> 8); + dir_backup.CheckSum1[1] = u8(csum1); + dir_backup.CheckSum2[0] = u8(csum2 >> 8); + dir_backup.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); + 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); - calc_checksumsBE((u16*)(((u8*)&bat_backup)+4),0xFFE,&csum1,&csum2); - bat_backup.CheckSum1[0]=u8(csum1>>8); - bat_backup.CheckSum1[1]=u8(csum1); - bat_backup.CheckSum2[0]=u8(csum2>>8); - bat_backup.CheckSum2[1]=u8(csum2); + calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2); + bat_backup.CheckSum1[0] = u8(csum1 >> 8); + bat_backup.CheckSum1[1] = u8(csum1); + bat_backup.CheckSum2[0] = u8(csum2 >> 8); + bat_backup.CheckSum2[1] = u8(csum2); return true; } - u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) { - if(!mcdFile) return 0; + if (!mcdFile) return 0; 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; - u32 ret = ImportFile(d,t); + if(!source.GetFileData(index, t, true)) return 0; + u32 ret = ImportFile(d,t,0); delete[] t; 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"); if (!gci) return OPENFAIL; @@ -653,7 +622,7 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2) std::string fileType; SplitPath(fileName, NULL, NULL, &fileType); - if( !strcasecmp(fileType.c_str(), ".gci") && !fileName2) + if( !strcasecmp(fileType.c_str(), ".gci")) offset = GCI; else { @@ -687,9 +656,9 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2) DEntry *d = new DEntry; fread(d, 1, 0x40, gci); - int fStart = ftell(gci); + int fStart = (int) ftell(gci); fseek(gci, 0, SEEK_END); - int length = ftell(gci) - fStart; + int length = (int) ftell(gci) - fStart; fseek(gci, offset + 0x40, SEEK_SET); switch(offset){ @@ -723,11 +692,11 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2) default: break; } - if (length == BE16(d->BlockCount) * 0x2000) + if (length != BE16(d->BlockCount) * 0x2000) { return LENGTHFAIL; } - if (ftell(gci) == offset + 0x40) // Verify correct file position + if (ftell(gci) != offset + 0x40) // Verify correct file position { return OPENFAIL; } @@ -735,21 +704,22 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2) u8 *t = new u8[size]; fread(t, 1, size, gci); fclose(gci); - u32 ret = 0; - if(fileName2) + u32 ret; + if(!fileName2.empty()) { - FILE * gci2 = fopen(fileName2, "wb"); + FILE * gci2 = fopen(fileName2.c_str(), "wb"); if (!gci2) return OPENFAIL; fseek(gci2, 0, SEEK_SET); - fwrite(d, 1, 0x40, gci2); + assert(fwrite(d, 1, 0x40, gci2)==0x40); int fileBlocks = BE16(d->BlockCount); fseek(gci2, 0x40, SEEK_SET); - fwrite(t, 0, 0x2000 * fileBlocks, gci2); + + assert(fwrite(t, 1, 0x2000 * fileBlocks, gci2)==(unsigned) (0x2000*fileBlocks)); fclose(gci2); + ret = GCS; } - else ret = ImportFile(*d, t); - - + else ret= ImportFile(*d, t,0); + delete []t; delete []tmp; delete d; @@ -759,18 +729,18 @@ int GCMemcard::ImportGci(const char *fileName, const char *fileName2) bool GCMemcard::ExportGci(u32 index, const char *fileName) { FILE *gci = fopen(fileName, "wb"); - if(!gci) return false; + if (!gci) return false; fseek(gci, 0, SEEK_SET); DEntry d; - if(!this->GetFileInfo(index, d)) return false; - fwrite(&d, 1, 0x40, gci); + if (!this->GetFileInfo(index, d)) return false; + assert(fwrite(&d, 1, 0x40, gci) == 0x40); 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); - fwrite(t, 1, 0x2000 * BE16(d.BlockCount), gci); + assert(fwrite(t, 1, 0x2000 * BE16(d.BlockCount), gci)== (unsigned) (0x2000 * BE16(d.BlockCount))); fclose(gci); delete []t; return true; @@ -778,16 +748,16 @@ bool GCMemcard::ExportGci(u32 index, const char *fileName) bool GCMemcard::Save() { - if(!mcdFile) return false; + if (!mcdFile) return false; FILE *mcd=(FILE*)mcdFile; - fseek(mcd,0,SEEK_SET); - fwrite(&hdr,1,0x2000,mcd); - fwrite(&dir,1,0x2000,mcd); - fwrite(&dir_backup,1,0x2000,mcd); - fwrite(&bat,1,0x2000,mcd); - fwrite(&bat_backup,1,0x2000,mcd); - fwrite(mc_data,1,mc_data_size,mcd); + fseek(mcd, 0, SEEK_SET); + assert(fwrite(&hdr, 1, 0x2000, mcd) == 0x2000); + assert(fwrite(&dir, 1, 0x2000, mcd) == 0x2000); + assert(fwrite(&dir_backup, 1, 0x2000, mcd) == 0x2000); + assert(fwrite(&bat, 1, 0x2000 ,mcd) == 0x2000); + assert(fwrite(&bat_backup, 1, 0x2000, mcd) == 0x2000); + assert(fwrite(mc_data, 1, mc_data_size, mcd) == mc_data_size); return true; } @@ -798,28 +768,28 @@ bool GCMemcard::IsOpen() GCMemcard::GCMemcard(const char *filename) { - FILE *mcd=fopen(filename,"r+b"); - mcdFile=mcd; - if(!mcd) return; + FILE *mcd = fopen(filename,"r+b"); + mcdFile = mcd; + if (!mcd) return; - fseek(mcd,0x0000,SEEK_SET); - assert(fread(&hdr, 1,0x2000,mcd)==0x2000); - assert(fread(&dir, 1,0x2000,mcd)==0x2000); - assert(fread(&dir_backup,1,0x2000,mcd)==0x2000); - assert(fread(&bat, 1,0x2000,mcd)==0x2000); - assert(fread(&bat_backup,1,0x2000,mcd)==0x2000); + fseek(mcd, 0x0000, SEEK_SET); + assert(fread(&hdr, 1, 0x2000, mcd) == 0x2000); + assert(fread(&dir, 1, 0x2000, mcd) == 0x2000); + assert(fread(&dir_backup, 1, 0x2000, mcd) == 0x2000); + assert(fread(&bat, 1, 0x2000, mcd) == 0x2000); + assert(fread(&bat_backup, 1, 0x2000, mcd) == 0x2000); u32 csums = TestChecksums(); - if(csums&1) + if (csums&1) { // header checksum error! // 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! // 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! // TODO: fail to load @@ -861,23 +831,17 @@ GCMemcard::GCMemcard(const char *filename) // bat = bat_backup; // needed? } - fseek(mcd,0xa000,SEEK_SET); + fseek(mcd, 0xa000, SEEK_SET); - assert(BE16(hdr.Size)!=0xFFFF); - mc_data_size=(((u32)BE16(hdr.Size)*16)-5)*0x2000; + assert(BE16(hdr.Size) != 0xFFFF); + mc_data_size = (((u32)BE16(hdr.Size) * 16) - 5) * 0x2000; mc_data = new u8[mc_data_size]; - size_t read = fread(mc_data,1,mc_data_size,mcd); - assert(mc_data_size==read); + size_t read = fread(mc_data, 1, mc_data_size, mcd); + assert(mc_data_size == read); } GCMemcard::~GCMemcard() { fclose((FILE*)mcdFile); } - -void varSwap(u8 *valueA,u8 *valueB){ - u8 temp = *valueA; - *valueA = *valueB; - *valueB = temp; -} diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h index c51bdd849f..878fea369a 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h @@ -28,7 +28,10 @@ enum OPENFAIL, GCI, SAV = 0x80, - GCS = 0x110 + GCS = 0x110, + OUTOFBLOCKS, + OUTOFDIRENTRIES, + NOMEMCARD }; class GCMemcard @@ -155,13 +158,17 @@ public: u32 GetFileSize(u32 index); // 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 bool RemoveFile(u32 index); // 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 u32 CopyFrom(GCMemcard& source, u32 index); @@ -170,7 +177,7 @@ public: bool ExportGci(u32 index, const char* fileName); // 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 bool ReadBannerRGBA8(u32 index, u32* buffer);