diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 5e1389c1fd..668b869ffa 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -81,6 +81,7 @@ BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) EVT_BUTTON(ID_GCISAVERIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_GCIOPENLEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_GCISAVELEFT,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_CONVERTTOGCI,CMemcardManager::CopyDeleteClick) EVT_FILEPICKER_CHANGED(ID_MEMCARD1PATH,CMemcardManager::OnPathChange) EVT_FILEPICKER_CHANGED(ID_MEMCARD2PATH,CMemcardManager::OnPathChange) END_EVENT_TABLE() @@ -119,6 +120,9 @@ void CMemcardManager::CreateGUIControls() m_GciSaveLeft = new wxButton(this, ID_GCISAVELEFT, wxT("<-Export GCI"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_GciOpenRight = new wxButton(this, ID_GCIOPENRIGHT, wxT("Import GCI->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_GciSaveRight = new wxButton(this, ID_GCISAVERIGHT, wxT("Export GCI->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + //Added to test GCS and SAV import, until ImportFile is fixed + //rather than needing to import and then export + m_ConvertToGci = new wxButton(this, ID_CONVERTTOGCI, wxT("Convert to GCI"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_DeleteLeft = new wxButton(this, ID_DELETELEFT, wxT("<-Delete"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_DeleteRight = new wxButton(this, ID_DELETERIGHT, wxT("Delete->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); @@ -154,6 +158,8 @@ void CMemcardManager::CreateGUIControls() sButtons->Add(m_GciOpenLeft, 0, wxEXPAND, 5); sButtons->Add(m_GciSaveLeft, 0, wxEXPAND, 5); sButtons->AddStretchSpacer(1); + sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(1); sButtons->Add(m_GciOpenRight, 0, wxEXPAND, 5); sButtons->Add(m_GciSaveRight, 0, wxEXPAND, 5); sButtons->AddStretchSpacer(1); @@ -227,22 +233,56 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) memoryCard[0]->Save(); } break; + case ID_CONVERTTOGCI: + {//Wont compile without brackets?? VC++ Express + wxString temp = wxFileSelector(_T("Select the save file to convert"), + wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format + ( + _T("Gamecube save files(*.gcs,*.sav)|*.gcs;*.sav|" + "MadCatz Gameshark files(*.gcs)|*.gcs|" + "Datel MaxDrive/Pro files(*.sav)|*.sav"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr + ), + wxFD_OPEN | wxFD_FILE_MUST_EXIST); + const char * fileName = temp.ToAscii(); + wxString temp2 = wxFileSelector(_T("Save GCI as.."), + wxEmptyString, wxEmptyString, _T(".gci"), wxString::Format + ( + _T("GCI File(*.gci)|*.gci"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr + ), + wxFD_OVERWRITE_PROMPT|wxFD_SAVE); + const char * fileName2 = temp2.ToAscii(); + + int len = temp.length(); + if(len>0) + { + memoryCard[0]->ImportGci(fileName,len,fileName2); + } + } + break; case ID_GCIOPENLEFT: if (memoryCard[0] != NULL) { wxString temp = wxFileSelector(_T("Select the GCI file to import"), wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format ( - _T("GCI File(*.gci)|*.gci|All files (%s)|%s"), + _T("Gamecube save files(*.gci,*.gcs,*.sav)|*.gci;*.gcs;*.sav|" + "Native GCI files (*.gci)|*.gci|" + "MadCatz Gameshark files(*.gcs)|*.gcs|" + "Datel MaxDrive/Pro files(*.sav)|*.sav"), wxFileSelectorDefaultWildcardStr, wxFileSelectorDefaultWildcardStr ), wxFD_OPEN | wxFD_FILE_MUST_EXIST); const char * fileName = temp.ToAscii(); - if (temp.length()>0) + int len = temp.length(); + if(len>0) { - memoryCard[0]->AddGci(fileName); + memoryCard[0]->ImportGci(fileName,len,0); memoryCard[0]->Save(); ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); } @@ -254,16 +294,19 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) wxString temp = wxFileSelector(_T("Select the GCI file to import"), wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format ( - _T("GCI File(*.gci)|*.gci|All files (%s)|%s"), + _T("Gamecube save files(*.gci,*.gcs,*.sav)|*.gci;*.gcs;*.sav|" + "Native GCI files (*.gci)|*.gci|" + "MadCatz Gameshark files(*.gcs)|*.gcs|" + "Datel MaxDrive/Pro files(*.sav)|*.sav"), wxFileSelectorDefaultWildcardStr, wxFileSelectorDefaultWildcardStr ), wxFD_OPEN | wxFD_FILE_MUST_EXIST); const char * fileName = temp.ToAscii(); - - if (temp.length()>0) + int len = temp.length(); + if(len>0) { - memoryCard[1]->AddGci(fileName); + memoryCard[1]->ImportGci(fileName,len,0); memoryCard[1]->Save(); ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); } @@ -283,7 +326,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) const char * fileName = temp.ToAscii(); if (temp.length()>0) - memoryCard[0]->SaveGci(index0, fileName); + memoryCard[0]->ExportGci(index0, fileName); } break; case ID_GCISAVERIGHT: @@ -300,7 +343,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) const char * fileName = temp.ToAscii(); if (temp.length()>0) - memoryCard[1]->SaveGci(index1, fileName); + memoryCard[1]->ExportGci(index1, fileName); } break; case ID_DELETELEFT: diff --git a/Source/Core/DolphinWX/Src/MemcardManager.h b/Source/Core/DolphinWX/Src/MemcardManager.h index 77dd862d87..e7b7abf1fa 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.h +++ b/Source/Core/DolphinWX/Src/MemcardManager.h @@ -14,7 +14,7 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -//updated to 677 + #ifndef __MEMCARD_MANAGER_h__ #define __MEMCARD_MANAGER_h__ @@ -50,6 +50,7 @@ class CMemcardManager wxButton *m_GciSaveLeft; wxButton *m_GciOpenRight; wxButton *m_GciSaveRight; + wxButton *m_ConvertToGci; wxButton *m_DeleteLeft; wxButton *m_DeleteRight; wxStaticBoxSizer *sMemcard1; @@ -72,6 +73,7 @@ class CMemcardManager ID_GCISAVELEFT, ID_GCIOPENRIGHT, ID_GCIOPENLEFT, + ID_CONVERTTOGCI, ID_MEMCARD1LIST, ID_MEMCARD2LIST, ID_DUMMY_VALUE_ //don't remove this value unless you have other enum values diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp index 34bd84ffab..aa3ef3109f 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp @@ -19,8 +19,8 @@ #include "stdafx.h" #endif #include -#include #include +#include "wx/ffile.h" #include "GCMemcard.h" @@ -609,37 +609,139 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) return ret; } -u32 GCMemcard::AddGci(const char *fileName) +u32 GCMemcard::ImportGci(const char *fileName, int endFile, const char *fileName2) { - if(!mcdFile) return 0; + if(!mcdFile && !fileName2) return 0; - FILE *gci=fopen(fileName,"rb"); + wxFFile gci(fileName,"rb"); + if(!gci.IsOpened())return 0; - if(!gci) return 0; + enum + { + GCI = 0, + SAV = 0x80, + GCS = 0x110 + }; + int offset; + char * tmp = new char[0xD]; + u16 tmpU16; + const char * fileType= (char*)fileName+ endFile-3; + + if(!_stricmp(fileType,"gci") && !fileName2)//Extension can be either case + offset = GCI; + else + { + gci.Read(tmp,0xD); + if(!_stricmp(fileType,"gcs"))//Extension can be either case + { + if(!memcmp(tmp,"GCSAVE",6)) //Header must be uppercase + offset = GCS; + else + { + //TODO error message, file has gsc extension but does not have a correct header + return 0; + } + } + else{ + if(!_stricmp(fileType,"sav"))//Extension can be either case + { + if(!memcmp(tmp,"DATELGC_SAVE",0xC))//Header must be uppercase + offset = SAV; + else + { + //TODO error message, file has sav extension but does not have a correct header + return 0; + } + } + else + { + //TODO error message, file has invalid extension + return 0; + } + } + } + gci.Seek(offset,wxFromStart); + DEntry *d = new DEntry; - fread(d,1,0x40,gci); + gci.Read(d,0x40); + + switch(offset){ + case GCS: + //field containing the Block count as displayed within the GameSaves software + //is not stored in the GCS file. + //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" + tmpU16 =(((int)gci.Length()-offset-0x40)/0x2000); + if(tmpU16<0x100){ + d->BlockCount[1] = (u8)tmpU16; + } + else{ + d->BlockCount[0] = (u8)(tmpU16-0xFF); + d->BlockCount[1] = 0xFF; + } + break; + case SAV: + //swap byte pairs + //0x2C and 0x2D,0x2E and 0x2F,0x30 and 0x31,0x32 and 0x33,0x34 and 0x35, + //0x36 and 0x37,0x38 and 0x39,0x3A and 0x3B,0x3C and 0x3D,0x3E and 0x3F. + SWAP((d->ImageOffset)); + SWAP(&(d->ImageOffset[2])); + SWAP((d->IconFmt)); + SWAP((d->AnimSpeed)); + varSwap(&d->Permissions,&d->CopyCounter); + SWAP((d->FirstBlock)); + SWAP((d->BlockCount)); + SWAP((d->Unused2)); + SWAP((d->CommentsAddr)); + SWAP(&(d->CommentsAddr[2])); + break; + default: + break; + } + //TODO verify file length + assert(((int)gci.Length()-offset)== ((BE16(d->BlockCount)* 0x2000) + 0x40)); + u32 size=BE16((d->BlockCount))*0x2000; u8 *t = new u8[size]; - fread(t,1,size,gci); - u32 ret = ImportFile(*d,t); + gci.Read(t,size); + + gci.Close(); + + u32 ret = 0; + if(!fileName2) + { + wxFFile gci2(fileName2,"wb"); + if(!gci2.IsOpened())return 0; + gci2.Seek(0,wxFromStart); + gci2.Write(d,0x40); + int fileBlocks=BE16(d->BlockCount); + gci2.Seek(0x40,wxFromStart); + gci2.Write(t,0x2000*fileBlocks); + gci2.Close(); + } + else ret = ImportFile(*d,t); + + delete[] t; + delete[] tmp; delete d; return ret; } -bool GCMemcard::SaveGci(u32 index, const char *fileName) +bool GCMemcard::ExportGci(u32 index, const char *fileName) { - FILE *gci=fopen(fileName,"wb"); - - if(!gci) return false; - - fseek(gci,0,SEEK_SET); + wxFFile gci(fileName,"wb"); + + if(!gci.IsOpened())return false; + + gci.Seek(0,wxFromStart); DEntry d; if(!this->GetFileInfo(index,d)) return false; - fwrite(&d,1,0x40,gci); + gci.Write(&d,0x40); u8 *t = new u8[this->GetFileSize(index)*0x2000]; @@ -647,10 +749,10 @@ bool GCMemcard::SaveGci(u32 index, const char *fileName) int fileBlocks=BE16(d.BlockCount); - fseek(gci,0x40,SEEK_SET); - fwrite(t,1,0x2000*fileBlocks,gci); + gci.Seek(0x40,wxFromStart); + gci.Write(t,0x2000*fileBlocks); - fclose(gci); + gci.Close(); delete[] t; return true; @@ -753,3 +855,9 @@ GCMemcard::~GCMemcard() { fclose((FILE*)mcdFile); } + +void varSwap(u8 *valueA,u8 *valueB){ + u8 temp = *valueA; + *valueA = *valueB; + *valueB = temp; +} \ No newline at end of file diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h index d787c4a80a..e489861685 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h @@ -15,12 +15,18 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ + #pragma once typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; + +#define SWAP(a) (varSwap(a,a+sizeof(u8))); + +void varSwap(u8 *valueA,u8 *valueB); + u16 __inline bswap16(u16 s) { return (s>>8) | (s<<8); @@ -178,10 +184,10 @@ public: u32 CopyFrom(GCMemcard& source, u32 index); // writes a .gci file to disk containing index - bool SaveGci(u32 index, const char* fileName); + bool ExportGci(u32 index, const char* fileName); - // reads a .gci file and calls ImportFile - u32 AddGci(const char* fileName); + // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file + u32 ImportGci(const char* fileName, int endFile,const char* fileName2); // reads the banner image bool ReadBannerRGBA8(u32 index, u32* buffer);