diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 971dc64875..2bba44fb20 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -74,7 +74,8 @@ BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) EVT_CLOSE(CMemcardManager::OnClose) EVT_BUTTON(ID_COPYTOLEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_COPYTORIGHT,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_FIXCHECKSUM,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_FIXCHECKSUMLEFT,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_FIXCHECKSUMRIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETELEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_DELETERIGHT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_SAVEIMPORTRIGHT,CMemcardManager::CopyDeleteClick) @@ -82,6 +83,10 @@ BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) EVT_BUTTON(ID_SAVEIMPORTLEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_SAVEEXPORTLEFT,CMemcardManager::CopyDeleteClick) EVT_BUTTON(ID_CONVERTTOGCI,CMemcardManager::CopyDeleteClick) + EVT_BUTTON(ID_MEMCARD1PREVPAGE, CMemcardManager::OnPageChange) + EVT_BUTTON(ID_MEMCARD1NEXTPAGE, CMemcardManager::OnPageChange) + EVT_BUTTON(ID_MEMCARD2PREVPAGE, CMemcardManager::OnPageChange) + EVT_BUTTON(ID_MEMCARD2NEXTPAGE, CMemcardManager::OnPageChange) EVT_FILEPICKER_CHANGED(ID_MEMCARD1PATH,CMemcardManager::OnPathChange) EVT_FILEPICKER_CHANGED(ID_MEMCARD2PATH,CMemcardManager::OnPathChange) END_EVENT_TABLE() @@ -110,29 +115,39 @@ CMemcardManager::~CMemcardManager() void CMemcardManager::CreateGUIControls() { + t_StatusLeft = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString); + t_StatusRight = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString); + // buttons 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); + m_FixChecksumLeft = new wxButton(this, ID_FIXCHECKSUMLEFT, wxT("<-Fix Checksum"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_FixChecksumRight = new wxButton(this, ID_FIXCHECKSUMRIGHT, wxT("Fix Checksum->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_SaveImportLeft = new wxButton(this, ID_SAVEIMPORTLEFT, wxT("<-Import GCI"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); - m_SaveExportLeft = new wxButton(this, ID_SAVEEXPORTLEFT, wxT("<-Export GCI"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_SaveImportRight = new wxButton(this, ID_SAVEIMPORTRIGHT, wxT("Import GCI->"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + + m_SaveExportLeft = new wxButton(this, ID_SAVEEXPORTLEFT, wxT("<-Export GCI"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_SaveExportRight = new wxButton(this, ID_SAVEEXPORTRIGHT, 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); + m_Memcard1PrevPage = new wxButton(this, ID_MEMCARD1PREVPAGE, wxT("Prev Page"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_Memcard2PrevPage = new wxButton(this, ID_MEMCARD2PREVPAGE, wxT("Prev Page"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + + m_Memcard1NextPage = new wxButton(this, ID_MEMCARD1NEXTPAGE, wxT("Next Page"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_Memcard2NextPage = new wxButton(this, ID_MEMCARD2NEXTPAGE, wxT("Next Page"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + // Sizers that double as wxStaticBoxes sMemcard1 = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Memory Card 1")); sMemcard2 = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Memory Card 2")); // Create the controls for both memcards - // Loading invalid .raw files still crash the app, but eh, needed this for testing + // Loading invalid .raw files should no longer crash the app m_Memcard1Path = new wxFilePickerCtrl(this, ID_MEMCARD1PATH, wxEmptyString, wxT("Choose a memory card:"), wxT("Raw memcards (*.raw)|*.raw"), wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL|wxFLP_FILE_MUST_EXIST|wxFLP_OPEN); m_Memcard2Path = new wxFilePickerCtrl(this, ID_MEMCARD2PATH, wxEmptyString, wxT("Choose a memory card:"), @@ -153,7 +168,8 @@ void CMemcardManager::CreateGUIControls() 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->Add(m_FixChecksumLeft, 0, wxEXPAND, 5); + sButtons->Add(m_FixChecksumRight, 0, wxEXPAND, 5); sButtons->AddStretchSpacer(1); sButtons->Add(m_SaveImportLeft, 0, wxEXPAND, 5); sButtons->Add(m_SaveExportLeft, 0, wxEXPAND, 5); @@ -167,19 +183,47 @@ void CMemcardManager::CreateGUIControls() sButtons->Add(m_DeleteRight, 0, wxEXPAND, 5); sButtons->AddStretchSpacer(1); + sPagesLeft = new wxBoxSizer(wxHORIZONTAL); + sPagesRight = new wxBoxSizer(wxHORIZONTAL); + + sPagesLeft->Add(m_Memcard1PrevPage, 0, wxEXPAND|wxALL, 1); + sPagesLeft->Add(t_StatusLeft,0, wxEXPAND|wxALL, 5); + sPagesLeft->Add(0, 0, 1, wxEXPAND|wxALL, 0); + sPagesLeft->Add(m_Memcard1NextPage, 0, wxEXPAND|wxALL, 1); + sPagesRight->Add(m_Memcard2PrevPage, 0, wxEXPAND|wxALL, 1); + sPagesRight->Add(t_StatusRight, 0, wxEXPAND|wxALL, 5); + sPagesRight->Add(0, 0, 1, wxEXPAND|wxALL, 0); + sPagesRight->Add(m_Memcard2NextPage, 0, wxEXPAND|wxALL, 1); + sMemcard1->Add(m_Memcard1Path, 0, wxEXPAND|wxALL, 5); - sMemcard1->Add(m_MemcardList[0], 1, wxEXPAND|wxALL, 5); + sMemcard1->Add(m_MemcardList[0], 1, wxEXPAND|wxALL, 5); + sMemcard1->Add(sPagesLeft, 0, wxEXPAND|wxALL, 1); sMemcard2->Add(m_Memcard2Path, 0, wxEXPAND|wxALL, 5); sMemcard2->Add(m_MemcardList[1], 1, wxEXPAND|wxALL, 5); + sMemcard2->Add(sPagesRight, 0, wxEXPAND|wxALL, 1); sMain = new wxBoxSizer(wxHORIZONTAL); sMain->Add(sMemcard1, 1, wxEXPAND|wxALL, 5); sMain->Add(sButtons, 0, wxEXPAND, 0); sMain->Add(sMemcard2, 1, wxEXPAND|wxALL, 5); - + this->SetSizer(sMain); sMain->SetSizeHints(this); Fit(); + m_Memcard1PrevPage->Disable(); + m_Memcard1NextPage->Disable(); + m_Memcard2PrevPage->Disable(); + m_Memcard2NextPage->Disable(); + m_CopyToLeft->Disable(); + m_CopyToRight->Disable(); + m_FixChecksumLeft->Disable(); + m_FixChecksumRight->Disable(); + m_SaveImportLeft->Disable(); + m_SaveExportLeft->Disable(); + m_SaveImportRight->Disable(); + m_SaveExportRight->Disable(); + m_DeleteLeft->Disable(); + m_DeleteRight->Disable(); } void CMemcardManager::OnClose(wxCloseEvent& WXUNUSED (event)) @@ -192,10 +236,100 @@ void CMemcardManager::OnPathChange(wxFileDirPickerEvent& event) switch (event.GetId()) { case ID_MEMCARD1PATH: - ReloadMemcard(event.GetPath().mb_str(), 0); + page1 = 0; + if (m_Memcard1PrevPage->IsEnabled()) m_Memcard1PrevPage->Disable(); + if (!strcasecmp(m_Memcard1Path->GetPath().mb_str(),m_Memcard2Path->GetPath().mb_str())) + { + wxMessageBox(wxT("Memcard already opened"), wxT("Error"), wxOK|wxICON_ERROR); + m_Memcard1Path->SetPath(wxEmptyString); + m_MemcardList[0]->ClearAll(); + t_StatusLeft->SetLabel(wxEmptyString); + } + else if (ReloadMemcard(event.GetPath().mb_str(), 0, page1)) + { + m_FixChecksumLeft->Enable(); + m_SaveImportLeft->Enable(); + m_SaveExportLeft->Enable(); + m_DeleteLeft->Enable(); + break; + } + m_Memcard1Path->SetPath(wxEmptyString); + m_MemcardList[0]->ClearAll(); + t_StatusLeft->SetLabel(wxEmptyString); + m_FixChecksumLeft->Disable(); + m_SaveImportLeft->Disable(); + m_SaveExportLeft->Disable(); + m_DeleteLeft->Disable(); + m_Memcard1PrevPage->Disable(); + m_Memcard1NextPage->Disable(); break; case ID_MEMCARD2PATH: - ReloadMemcard(event.GetPath().mb_str(), 1); + page2 = 0; + if (m_Memcard2PrevPage->IsEnabled()) m_Memcard2PrevPage->Disable(); + if (!strcasecmp(m_Memcard1Path->GetPath().mb_str(),m_Memcard2Path->GetPath().mb_str())) + { + wxMessageBox(wxT("Memcard already opened"), wxT("Error"), wxOK|wxICON_ERROR); + } + else if (ReloadMemcard(event.GetPath().mb_str(), 1, page2)) + { + m_FixChecksumRight->Enable(); + m_SaveImportRight->Enable(); + m_SaveExportRight->Enable(); + m_DeleteRight->Enable(); + break; + } + m_Memcard2Path->SetPath(wxEmptyString); + m_MemcardList[1]->ClearAll(); + t_StatusRight->SetLabel(wxEmptyString); + m_FixChecksumRight->Disable(); + m_SaveImportRight->Disable(); + m_SaveExportRight->Disable(); + m_DeleteRight->Disable(); + m_Memcard2PrevPage->Disable(); + m_Memcard2NextPage->Disable(); + break; + } + if (m_DeleteRight->IsEnabled() && m_DeleteLeft->IsEnabled()) + { + m_CopyToLeft->Enable(); + m_CopyToRight->Enable(); + } + else + { + m_CopyToLeft->Disable(); + m_CopyToRight->Disable(); + } +} + +void CMemcardManager::OnPageChange(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case ID_MEMCARD1NEXTPAGE: + if (!m_Memcard1PrevPage->IsEnabled()) m_Memcard1PrevPage->Enable(); + if (!m_Memcard1NextPage->IsEnabled()) m_Memcard1NextPage->Enable(); + page1++; + if (page1 == 7) m_Memcard1NextPage->Disable(); + ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0, page1); + break; + case ID_MEMCARD2NEXTPAGE: + if (!m_Memcard2PrevPage->IsEnabled()) m_Memcard2PrevPage->Enable(); + if (!m_Memcard2NextPage->IsEnabled()) m_Memcard2NextPage->Enable(); + page2++; + if (page2 == 7) m_Memcard2NextPage->Disable(); + ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1, page2); + break; + case ID_MEMCARD1PREVPAGE: + if (!m_Memcard1NextPage->IsEnabled()) m_Memcard1NextPage->Enable(); + page1--; + if (page1 == 0) m_Memcard1PrevPage->Disable(); + ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0, page1); + break; + case ID_MEMCARD2PREVPAGE: + if (!m_Memcard2NextPage->IsEnabled()) m_Memcard2NextPage->Enable(); + page2--; + if (page2 == 0) m_Memcard2PrevPage->Disable(); + ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1, page2); break; } } @@ -207,7 +341,6 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) int slot = 1; int index2 = index1; std::string fileName2(""); - int freeBlocks = 0; wxString blocksOpen; switch (event.GetId()) @@ -225,11 +358,15 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) break; case SUCCESS: memoryCard[0]->Save(); - ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); + ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0, 0); break; } } + else + { + wxMessageBox(wxT("You have not selected a save to copy"), wxT("Error"), wxOK|wxICON_ERROR); + } break; case ID_COPYTORIGHT: if ((index0 != -1) && (memoryCard[1] != NULL)) @@ -246,19 +383,29 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) break; case SUCCESS: memoryCard[1]->Save(); - ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1); + ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1, 0); break; } } + else + { + wxMessageBox(wxT("You have not selected a save to copy"), wxT("Error"), wxOK|wxICON_ERROR); + } break; - case ID_FIXCHECKSUM: - if (memoryCard[0] != NULL) + case ID_FIXCHECKSUMLEFT: + slot = 0; + case ID_FIXCHECKSUMRIGHT: + if (memoryCard[slot] != NULL) { // Fix checksums and save the changes - memoryCard[0]->FixChecksums() ? wxMessageBox(wxT("The checksum was successfully fixed"), wxT("Success"), wxOK) + memoryCard[slot]->FixChecksums() ? wxMessageBox(wxT("The checksum was successfully fixed"), wxT("Success"), wxOK) : wxMessageBox(wxT("The checksum could not be successfully fixed"), wxT("Error"), wxOK|wxICON_ERROR); - memoryCard[0]->Save(); - } + memoryCard[slot]->Save(); + } + else + { + wxMessageBox(wxT("memorycard is not loaded"), wxT("Error"), wxOK|wxICON_ERROR); + } break; case ID_CONVERTTOGCI: fileName2 = "convert"; @@ -268,7 +415,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) case ID_SAVEIMPORTRIGHT: if (memoryCard[slot] != NULL || !fileName2.empty()) { - wxString temp = wxFileSelector(_T("Select the GCI file to import"), + wxString temp = wxFileSelector(_T("Select a save file to import"), wxEmptyString, wxEmptyString, wxEmptyString,wxString::Format ( _T("Gamecube save files(*.gci,*.gcs,*.sav)|*.gci;*.gcs;*.sav|" @@ -290,6 +437,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) wxFileSelectorDefaultWildcardStr ), wxFD_OVERWRITE_PROMPT|wxFD_SAVE); + if (temp2.empty()) break; fileName2 = temp2.mb_str(); } if (temp.length() > 0) @@ -320,8 +468,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) wxT("Success"), wxOK); break; case OUTOFBLOCKS: - freeBlocks = BE16(memoryCard[slot]->bat.FreeBlocks); - blocksOpen.Printf(wxT("Only %d blocks available"), freeBlocks); + blocksOpen.Printf(wxT("Only %d blocks available"), memoryCard[slot]->GetFreeBlocks()); wxMessageBox(blocksOpen, wxT("Error"), wxOK|wxICON_ERROR); break; case OUTOFDIRENTRIES: @@ -342,12 +489,16 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) break; default: memoryCard[slot]->Save(); - slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) - : ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); + slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1, 0) + : ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0, 0); break; } } } + else + { + wxMessageBox(wxT("Memory card is not loaded"), wxT("Error"), wxOK|wxICON_ERROR); + } break; case ID_SAVEEXPORTLEFT: slot=0; @@ -387,6 +538,10 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) } } } + else + { + wxMessageBox(wxT("You have not selected a save to export"), wxT("Error"), wxOK|wxICON_ERROR); + } break; case ID_DELETELEFT: slot=0; @@ -406,28 +561,41 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) break; case SUCCESS: memoryCard[slot]->Save(); - slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1) - : ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0); + slot == 1 ? ReloadMemcard(m_Memcard2Path->GetPath().mb_str(), 1, 0) + : ReloadMemcard(m_Memcard1Path->GetPath().mb_str(), 0, 0); break; } } + else + { + wxMessageBox(wxT("You have not selected a save to delete"), wxT("Error"), wxOK|wxICON_ERROR); + } break; } } -void CMemcardManager::ReloadMemcard(const char *fileName, int card) +bool CMemcardManager::ReloadMemcard(const char *fileName, int card, int page) { + wxString wxBlock; + wxString wxFirstBlock; + wxString wxLabel; + int j; + if (memoryCard[card]) delete memoryCard[card]; // TODO: add error checking and animate icons memoryCard[card] = new GCMemcard(fileName); + if (ReadError(memoryCard[card])) return false; + m_MemcardList[card]->Hide(); m_MemcardList[card]->ClearAll(); m_MemcardList[card]->InsertColumn(COLUMN_BANNER, _T("Banner")); m_MemcardList[card]->InsertColumn(COLUMN_TITLE, _T("Title")); m_MemcardList[card]->InsertColumn(COLUMN_COMMENT, _T("Comment")); m_MemcardList[card]->InsertColumn(COLUMN_ICON, _T("Icon")); + m_MemcardList[card]->InsertColumn(COLUMN_BLOCKS, _T("Blocks")); + m_MemcardList[card]->InsertColumn(COLUMN_FIRSTBLOCK, _T("First Block")); wxImageList *list = m_MemcardList[card]->GetImageList(wxIMAGE_LIST_SMALL); list->RemoveAll(); @@ -435,7 +603,7 @@ void CMemcardManager::ReloadMemcard(const char *fileName, int card) int nFiles = memoryCard[card]->GetNumFiles(); int *images = new int[nFiles*2]; - for (int i=0;iAdd(icon); } } - - for (int i=0;iGetComment1(i,title)) title[0]=0; - if (!memoryCard[card]->GetComment2(i,comment)) comment[0]=0; - int index = m_MemcardList[card]->InsertItem(i, wxT("row")); + if (!memoryCard[card]->GetComment1(j, title)) title[0]=0; + if (!memoryCard[card]->GetComment2(j, comment)) comment[0]=0; + int index = m_MemcardList[card]->InsertItem(j, wxT("row")); m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxString::FromAscii(title)); m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxString::FromAscii(comment)); + if (!memoryCard[card]->GetNumBlocks(j, &blocks)) blocks = 0; + wxBlock.Printf("%10d", blocks); + if (!memoryCard[card]->GetFirstBlock(j,&firstblock)) firstblock = 0; + wxFirstBlock.Printf("%10d", firstblock-4); + m_MemcardList[card]->SetItem(index,COLUMN_BLOCKS, wxBlock); + m_MemcardList[card]->SetItem(index,COLUMN_FIRSTBLOCK, wxFirstBlock); m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); - if (images[i]>=0) + if (images[j] >= 0) { - m_MemcardList[card]->SetItemImage(index, images[i*2]); - m_MemcardList[card]->SetItemColumnImage(index, COLUMN_ICON, images[i*2+1]); + m_MemcardList[card]->SetItemImage(index, images[j*2]); + m_MemcardList[card]->SetItemColumnImage(index, COLUMN_ICON, images[j*2+1]); } } + if (j == nFiles) + { + card ? m_Memcard2NextPage->Disable() : m_Memcard1NextPage->Disable(); + } + else + { + card ? m_Memcard2NextPage->Enable() : m_Memcard1NextPage->Enable(); + } + delete[] images; // Automatic column width and then show the list for (int i = 0; i < m_MemcardList[card]->GetColumnCount(); i++) @@ -511,4 +695,43 @@ void CMemcardManager::ReloadMemcard(const char *fileName, int card) m_MemcardList[card]->SetColumnWidth(i, wxLIST_AUTOSIZE); } m_MemcardList[card]->Show(); + wxLabel.Printf("%d Free Blocks; %d Free Dir Entries", + memoryCard[card]->GetFreeBlocks(), 127 - nFiles); + card ? t_StatusRight->SetLabel(wxLabel) : t_StatusLeft->SetLabel(wxLabel); + + return true; +} + +bool CMemcardManager::ReadError(GCMemcard *memcard) +{ + if (!memcard->fail[0]) return false; + wxString wxBlock; + if (memcard->fail[HDR_READ_ERROR]) wxMessageBox(wxT("Failed to read header correctly\n(0x0000-0x1FFF)"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[DIR_READ_ERROR]) wxMessageBox(wxT("Failed to read directory correctly\n(0x2000-0x3FFF)"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[DIR_BAK_READ_ERROR]) wxMessageBox(wxT("Failed to read directory backup correctly\n(0x4000-0x5FFF)"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[BAT_READ_ERROR]) wxMessageBox(wxT("Failed to read block allocation table correctly\n(0x6000-0x7FFF)"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[BAT_BAK_READ_ERROR]) wxMessageBox(wxT("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[HDR_CSUM_FAIL]) wxMessageBox(wxT("Header checksum failed"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[DIR_CSUM_FAIL]) + { + wxMessageBox(wxT("Directory checksum failed"), + wxT("Error"), wxOK|wxICON_ERROR); + wxMessageBox(wxT("Directory backup checksum failed"), + wxT("Error"), wxOK|wxICON_ERROR); + } + if (memcard->fail[BAT_CSUM_FAIL]) wxMessageBox(wxT("Block Allocation Table checksum failed"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[DATA_READ_FAIL]) wxMessageBox(wxT("Failed to read save data\n(0xA000-)\nMemcard may be truncated"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[HDR_SIZE_FFFF]) wxMessageBox(wxT("Memcard failed to load\n Card size is invalid"), + wxT("Error"), wxOK|wxICON_ERROR); + if (memcard->fail[NOTRAWORGCP]) wxMessageBox(wxT("File does not have a valid extension (.raw/.gcp)"), + wxT("Error"), wxOK|wxICON_ERROR); + return true; } diff --git a/Source/Core/DolphinWX/Src/MemcardManager.h b/Source/Core/DolphinWX/Src/MemcardManager.h index 962b4f78cb..7e8f8813a8 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.h +++ b/Source/Core/DolphinWX/Src/MemcardManager.h @@ -26,7 +26,6 @@ #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 @@ -42,10 +41,18 @@ class CMemcardManager DECLARE_EVENT_TABLE(); + int page1, + page2; + wxBoxSizer *sMain; + wxBoxSizer *sPagesLeft; + wxBoxSizer *sPagesRight; + wxStaticText *t_StatusLeft; + wxStaticText *t_StatusRight; wxButton *m_CopyToLeft; wxButton *m_CopyToRight; - wxButton *m_FixChecksum; + wxButton *m_FixChecksumLeft; + wxButton *m_FixChecksumRight; wxButton *m_SaveImportLeft; wxButton *m_SaveExportLeft; wxButton *m_SaveImportRight; @@ -53,6 +60,10 @@ class CMemcardManager wxButton *m_ConvertToGci; wxButton *m_DeleteLeft; wxButton *m_DeleteRight; + wxButton *m_Memcard1PrevPage; + wxButton *m_Memcard1NextPage; + wxButton *m_Memcard2PrevPage; + wxButton *m_Memcard2NextPage; wxStaticBoxSizer *sMemcard1; wxStaticBoxSizer *sMemcard2; wxFilePickerCtrl *m_Memcard1Path; @@ -64,11 +75,16 @@ class CMemcardManager { ID_COPYTORIGHT = 1000, ID_COPYTOLEFT, - ID_FIXCHECKSUM, + ID_FIXCHECKSUMRIGHT, + ID_FIXCHECKSUMLEFT, ID_DELETERIGHT, ID_DELETELEFT, ID_MEMCARD1PATH, ID_MEMCARD2PATH, + ID_MEMCARD1NEXTPAGE, + ID_MEMCARD1PREVPAGE, + ID_MEMCARD2NEXTPAGE, + ID_MEMCARD2PREVPAGE, ID_SAVEEXPORTRIGHT, ID_SAVEEXPORTLEFT, ID_SAVEIMPORTRIGHT, @@ -85,6 +101,8 @@ class CMemcardManager COLUMN_TITLE, COLUMN_COMMENT, COLUMN_ICON, + COLUMN_BLOCKS, + COLUMN_FIRSTBLOCK, NUMBER_OF_COLUMN }; @@ -93,9 +111,10 @@ class CMemcardManager void CreateGUIControls(); void OnClose(wxCloseEvent& event); void CopyDeleteClick(wxCommandEvent& event); - void ReloadMemcard(const char *fileName, int card); + bool ReloadMemcard(const char *fileName, int card, int page); + void OnPageChange(wxCommandEvent& event); void OnPathChange(wxFileDirPickerEvent& event); - void OnTimer(wxTimerEvent& event); + bool ReadError(GCMemcard *memcard); }; #endif diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp index 1efbbd3dfd..f284ee1e37 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp @@ -25,7 +25,6 @@ // i think there is support for this stuff in the common lib... if not there should be support -// and to get a file exentions there is a function called SplitPath() #define BE16(x) ((u16((x)[0])<<8) | u16((x)[1])) #define BE32(x) ((u32((x)[0])<<24) | (u32((x)[1])<<16) | (u32((x)[2])<<8) | u32((x)[3])) #define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8))); @@ -54,24 +53,30 @@ u32 __inline bswap32(u32 s) void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2) { - *c1 = 0;*c2 = 0; - for (u32 i = 0; i < num; ++i) - { - //weird warnings here - *c1 += bswap16(buf[i]); - *c2 += bswap16((u16)(buf[i] ^ 0xffff)); - } - if (*c1 == 0xffff) - { - *c1 = 0; - } - if (*c2 == 0xffff) - { - *c2 = 0; - } + *c1 = 0;*c2 = 0; + for (u32 i = 0; i < num; ++i) + { + //weird warnings here + *c1 += bswap16(buf[i]); + *c2 += bswap16((u16)(buf[i] ^ 0xffff)); + } + if (*c1 == 0xffff) + { + *c1 = 0; + } + if (*c2 == 0xffff) + { + *c2 = 0; + } } -u32 GCMemcard::GetNumFiles() +u16 GCMemcard::GetFreeBlocks(void) +{ + if (!mcdFile) return 0; + return BE16(bat.FreeBlocks); +} + +u32 GCMemcard::GetNumFiles() { if (!mcdFile) return 0; int j = 0; @@ -83,7 +88,7 @@ u32 GCMemcard::GetNumFiles() return j; } -bool GCMemcard::titlePresent(DEntry d) +bool GCMemcard::TitlePresent(DEntry d) { //TODO: Clean up this function bool equal = false; @@ -114,6 +119,20 @@ bool GCMemcard::titlePresent(DEntry d) return false; } +bool GCMemcard::GetNumBlocks(u32 index, u16* buffer) +{ + if (!mcdFile) return false; + *buffer = BE16(dir.Dir[index].BlockCount); + return true; +} + +bool GCMemcard::GetFirstBlock(u32 index, u16* buffer) +{ + if (!mcdFile) return false; + *buffer = BE16(dir.Dir[index].FirstBlock); + return true; +} + u32 GCMemcard::RemoveFile(u32 index) //index in the directory array { if (!mcdFile) return NOMEMCARD; @@ -130,7 +149,7 @@ u32 GCMemcard::RemoveFile(u32 index) //index in the directory array int i = index + 1; memset(&(dir.Dir[index]), 0xFF, 0x40); - + while (i < 127) { DEntry * d = new DEntry; @@ -196,7 +215,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) { return OUTOFBLOCKS; } - if (!remove && titlePresent(direntry)) return TITLEPRESENT; + if (!remove && TitlePresent(direntry)) return TITLEPRESENT; // find first free data block -- assume no freespace fragmentation int totalspace = (((u32)BE16(hdr.Size) * 16) - 5); @@ -293,9 +312,9 @@ u32 GCMemcard::GetFileData(u32 index, u8*dest, bool old) //index in the director { if (!mcdFile) return NOMEMCARD; - int block = BE16(dir.Dir[index].FirstBlock); - int saveLength = BE16(dir.Dir[index].BlockCount); - int memcardSize = BE16(hdr.Size) * 0x0010; + u16 block = BE16(dir.Dir[index].FirstBlock); + u16 saveLength = BE16(dir.Dir[index].BlockCount); + u16 memcardSize = BE16(hdr.Size) * 0x0010; if (block + saveLength > memcardSize) { @@ -308,27 +327,24 @@ u32 GCMemcard::GetFileData(u32 index, u8*dest, bool old) //index in the director } else { - assert(block != 0xFFFF); assert(block > 0); - do - { - memcpy(dest,mc_data + 0x2000 * (block - 5), 0x2000); - dest+=0x2000; + while (block != 0xffff) + { + 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); + u16 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 break; + } } return SUCCESS; } -u32 GCMemcard::GetFileSize(u32 index) //index in the directory array +u32 GCMemcard::GetFileSize(u32 index) //index in the directory array { if (!mcdFile) return 0; @@ -342,6 +358,7 @@ bool GCMemcard::GetFileInfo(u32 index, GCMemcard::DEntry& info) //index in the d info = dir.Dir[index]; return true; } + bool GCMemcard::GetFileName(u32 index, char *fn) //index in the directory array { if (!mcdFile) return false; @@ -387,14 +404,13 @@ bool GCMemcard::GetComment2(u32 index, char *fn) //index in the directory array u32 decode5A3(u16 val) { const int lut5to8[] = { 0x00,0x08,0x10,0x18,0x20,0x29,0x31,0x39, - 0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B, - 0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD, - 0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF}; + 0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B, + 0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD, + 0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF}; const int lut4to8[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, - 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; + 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF}; - int r,g,b,a; if ((val&0x8000)) { @@ -433,11 +449,11 @@ void decode5A3image(u32* dst, u16* src, int width, int height) void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height) { - for (int y = 0; y < height; y += 4) + for (int y = 0; y < height; y += 4) { - for (int x = 0; x < width; x += 8) + for (int x = 0; x < width; x += 8) { - for (int iy = 0; iy < 4; iy++, src += 8) + for (int iy = 0; iy < 4; iy++, src += 8) { u32 *tdst = dst+(y+iy)*width+x; for (int ix = 0; ix < 8; ix++) @@ -486,7 +502,7 @@ bool GCMemcard::ReadBannerRGBA8(u32 index, u32* buffer) return true; } -u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) +u32 GCMemcard::ReadAnimRGBA8(u32 index, u32* buffer, u8 *delays) { if (!mcdFile) return 0; @@ -614,7 +630,7 @@ bool GCMemcard::FixChecksums() 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); @@ -641,7 +657,7 @@ bool GCMemcard::FixChecksums() return true; } -u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) +u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) { if (!mcdFile) return NOMEMCARD; @@ -667,7 +683,7 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u32 index) return ret; } -s32 GCMemcard::ImportGci(const char *fileName, std::string fileName2) +s32 GCMemcard::ImportGci(const char *fileName, std::string fileName2) { if (fileName2.empty() && !mcdFile) return OPENFAIL; @@ -685,7 +701,7 @@ s32 GCMemcard::ImportGci(const char *fileName, std::string fileName2) { fread(tmp, 1, 0xD, gci); if (!strcasecmp(fileType.c_str(), ".gcs")) - { + { if (!memcmp(tmp, "GCSAVE", 6)) // Header must be uppercase offset = GCS; else @@ -760,7 +776,7 @@ s32 GCMemcard::ImportGci(const char *fileName, std::string fileName2) u32 size = BE16((d->BlockCount)) * 0x2000; u8 *t = new u8[size]; fread(t, 1, size, gci); - fclose(gci); + fclose(gci); u32 ret; if(!fileName2.empty()) { @@ -805,7 +821,6 @@ u32 GCMemcard::ExportGci(u32 index, const char *fileName) break; } - fseek(gci, 0x40, SEEK_SET); assert(fwrite(t, 1, 0x2000 * BE16(d.BlockCount), gci)== (unsigned) (0x2000 * BE16(d.BlockCount))); fclose(gci); @@ -837,21 +852,62 @@ GCMemcard::GCMemcard(const char *filename) { FILE *mcd = fopen(filename,"r+b"); mcdFile = mcd; + fail[0] = true; if (!mcd) return; + for(int i=0;i<12;i++)fail[i]=false; + + //This function can be removed once more about hdr is known and we can check for a valid header + std::string fileType; + SplitPath(filename, NULL, NULL, &fileType); + if (strcasecmp(fileType.c_str(), ".raw") && strcasecmp(fileType.c_str(), ".gcp")) + { + fail[0] = true; + fail[NOTRAWORGCP] = true; + 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); + if (fread(&hdr, 1, 0x2000, mcd) != 0x2000) + { + fail[0] = true; + fail[HDR_READ_ERROR] = true; + return; + } + if (fread(&dir, 1, 0x2000, mcd) != 0x2000) + { + fail[0] = true; + fail[DIR_READ_ERROR] = true; + return; + } + if (fread(&dir_backup, 1, 0x2000, mcd) != 0x2000) + { + fail[0] = true; + fail[DIR_BAK_READ_ERROR] = true; + return; + } + if (fread(&bat, 1, 0x2000, mcd) != 0x2000) + { + fail[0] = true; + fail[BAT_READ_ERROR] = true; + return; + } + if (fread(&bat_backup, 1, 0x2000, mcd) != 0x2000) + { + fail[0] = true; + fail[BAT_BAK_READ_ERROR] = true; + return; + } u32 csums = TestChecksums(); if (csums&1) { // header checksum error! - // TODO: fail to load + // invalid files do not always get here + fail[0] = true; + fail[HDR_CSUM_FAIL] = true; + return; } if (csums&2) // directory checksum error! @@ -859,7 +915,9 @@ GCMemcard::GCMemcard(const char *filename) if (csums&4) { // backup is also wrong! - // TODO: fail to load + fail[0] = true; + fail[DIR_CSUM_FAIL] = true; + return; } else { @@ -877,7 +935,9 @@ GCMemcard::GCMemcard(const char *filename) if (csums&16) { // backup is also wrong! - // TODO: fail to load + fail[0] = true; + fail[BAT_CSUM_FAIL] = true; + return; } else { @@ -900,15 +960,30 @@ GCMemcard::GCMemcard(const char *filename) fseek(mcd, 0xa000, SEEK_SET); - assert(BE16(hdr.Size) != 0xFFFF); - mc_data_size = (((u32)BE16(hdr.Size) * 16) - 5) * 0x2000; - mc_data = new u8[mc_data_size]; + u16 size = BE16(hdr.Size); + if ((size== 0x0080) || (size == 0x0040) || + (size == 0x0020) || (size == 0x0010) || + (size == 0x0008) || (size == 0x0004)) + { + mc_data_size = (((u32)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); + if (mc_data_size != read) + { + fail[0] = true; + fail[DATA_READ_FAIL] = true; + } + } + else + { + fail[0] = true; + fail[HDR_SIZE_FFFF] = true; + } } GCMemcard::~GCMemcard() { + if (!mcdFile) return; fclose((FILE*)mcdFile); } diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h index 9f5196e8b0..dc0ee0664f 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h @@ -27,6 +27,17 @@ enum SAVFAIL, OPENFAIL, GCI, + HDR_READ_ERROR, + DIR_READ_ERROR, + DIR_BAK_READ_ERROR, + BAT_READ_ERROR, + BAT_BAK_READ_ERROR, + HDR_CSUM_FAIL, + DIR_CSUM_FAIL, + BAT_CSUM_FAIL, + DATA_READ_FAIL, + HDR_SIZE_FFFF, + NOTRAWORGCP, SAV = 0x80, GCS = 0x110, OUTOFBLOCKS, @@ -38,9 +49,9 @@ enum FAIL }; - class GCMemcard { +private: void* mcdFile; u32 mc_data_size; @@ -48,8 +59,6 @@ class GCMemcard void calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2); -public: - #pragma pack(push,1) struct OSTime { u32 low; @@ -133,6 +142,9 @@ public: } bat,bat_backup; #pragma pack(pop) +public: + bool fail[12]; + // constructor GCMemcard(const char* fileName); @@ -148,7 +160,7 @@ public: u32 GetNumFiles(); // Returns true if title already on memcard - bool titlePresent(DEntry d); + bool TitlePresent(DEntry d); // read directory entry bool GetFileInfo(u32 index, DEntry& data); @@ -156,6 +168,12 @@ public: // buffer needs to be a char[32] or bigger bool GetFileName(u32 index, char* buffer); + bool GetNumBlocks(u32 index, u16* buffer); + + u16 GetFreeBlocks(void); + + bool GetFirstBlock(u32 index, u16* buffer); + // buffer needs to be a char[32] or bigger bool GetComment1(u32 index, char* buffer);