From 98993bfbd31f863832522d50f15795a811c0db5d Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Fri, 9 Dec 2011 14:58:58 -0800 Subject: [PATCH 01/10] fix the twocardsloaded settings, correctly disables the copy functions when only one card is loaded Signed-off-by: LPFaint99 --- Source/Core/DolphinWX/Src/MemcardManager.cpp | 21 +++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 98390122e2..89fc096b13 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -101,6 +101,7 @@ CMemcardManager::CMemcardManager(wxWindow* parent, wxWindowID id, const wxString memoryCard[SLOT_A]=NULL; memoryCard[SLOT_B]=NULL; + mcmSettings.twoCardsLoaded = false; if (!LoadSettings()) { itemsPerPage = 16; @@ -283,7 +284,7 @@ void CMemcardManager::ChangePath(int slot) m_PrevPage[slot]->Disable(); m_MemcardList[slot]->prevPage = false; } - if (!strcasecmp(m_MemcardPath[slot2]->GetPath().mb_str(), m_MemcardPath[slot]->GetPath().mb_str())) + if (!m_MemcardPath[SLOT_A]->GetPath().CmpNoCase(m_MemcardPath[SLOT_B]->GetPath())) { if(m_MemcardPath[slot]->GetPath().length()) PanicAlertT("Memcard already opened"); @@ -292,7 +293,10 @@ void CMemcardManager::ChangePath(int slot) { if (m_MemcardPath[slot]->GetPath().length() && ReloadMemcard(m_MemcardPath[slot]->GetPath().mb_str(), slot)) { - mcmSettings.twoCardsLoaded = true; + if (memoryCard[slot2]) + { + mcmSettings.twoCardsLoaded = true; + } m_SaveImport[slot]->Enable(); m_SaveExport[slot]->Enable(); m_Delete[slot]->Enable(); @@ -318,16 +322,9 @@ void CMemcardManager::ChangePath(int slot) } } } - if (m_Delete[SLOT_A]->IsEnabled() && m_Delete[SLOT_B]->IsEnabled()) - { - m_CopyFrom[SLOT_A]->Enable(); - m_CopyFrom[SLOT_B]->Enable(); - } - else - { - m_CopyFrom[SLOT_A]->Disable(); - m_CopyFrom[SLOT_B]->Disable(); - } + + m_CopyFrom[SLOT_A]->Enable(mcmSettings.twoCardsLoaded); + m_CopyFrom[SLOT_B]->Enable(mcmSettings.twoCardsLoaded); } void CMemcardManager::OnPageChange(wxCommandEvent& event) From d5c393fe96efc3a3dff46d59405789bc5aea46d8 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Fri, 9 Dec 2011 15:02:05 -0800 Subject: [PATCH 02/10] initial work on displaying, exporting, and deleting from memory cards that have gaps in the fst Conflicts: .gitignore Source/Core/DolphinWX/Src/MemcardManager.cpp Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 21 +++++++++++++++++ Source/Core/Core/Src/HW/GCMemcard.h | 1 + Source/Core/DolphinWX/Src/MemcardManager.cpp | 24 ++++++++++++-------- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index cab7d950a2..646c210b29 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -320,6 +320,27 @@ u8 GCMemcard::GetNumFiles() return j; } +u8 GCMemcard::GetFileIndex(u8 fileNumber) +{ + if (m_valid) + { + + u8 j = 0; + for (int i = 0; i < DIRLEN; i++) + { + if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) + { + if (j == fileNumber) + { + return i; + } + j++; + } + } + } + return -1; +} + u16 GCMemcard::GetFreeBlocks() { if (!m_valid) diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index 8c7baa4774..59cecded32 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -185,6 +185,7 @@ public: // get number of file entries in the directory u8 GetNumFiles(); + u8 GetFileIndex(u8 fileNumber); // get the free blocks from bat u16 GetFreeBlocks(); diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 89fc096b13..a7b999f7a6 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -493,6 +493,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot2 = SLOT_B; case ID_COPYFROM_A: index = slot2 ? index_B : index_A; + index = memoryCard[slot2]->GetFileIndex(index); if ((index != wxNOT_FOUND)) { CopyDeleteSwitch(memoryCard[slot]->CopyFrom(*memoryCard[slot2], index), slot); @@ -542,6 +543,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot=SLOT_A; index = index_A; case ID_SAVEEXPORT_B: + index = memoryCard[slot]->GetFileIndex(index); if (index != wxNOT_FOUND) { char tempC[10 + DENTRY_STRLEN], @@ -588,6 +590,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot = SLOT_A; index = index_A; case ID_DELETE_B: + index = memoryCard[slot]->GetFileIndex(index); if (index != wxNOT_FOUND) { CopyDeleteSwitch(memoryCard[slot]->RemoveFile(index), slot); @@ -628,18 +631,19 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) wxImageList *list = m_MemcardList[card]->GetImageList(wxIMAGE_LIST_SMALL); list->RemoveAll(); - int nFiles = memoryCard[card]->GetNumFiles(); + u8 nFiles = memoryCard[card]->GetNumFiles(); int *images = new int[nFiles*2]; - for (int i = 0;i < nFiles;i++) + for (u8 i = 0;i < nFiles;i++) { static u32 pxdata[96*32]; static u8 animDelay[8]; static u32 animData[32*32*8]; - int numFrames = memoryCard[card]->ReadAnimRGBA8(i,animData,animDelay); + u8 fileIndex = memoryCard[card]->GetFileIndex(i); + int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay); - if (!memoryCard[card]->ReadBannerRGBA8(i,pxdata)) + if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata)) { memset(pxdata,0,96*32*4); @@ -689,13 +693,15 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) char comment[DENTRY_STRLEN]; u16 blocks; u16 firstblock; + u8 fileIndex = memoryCard[card]->GetFileIndex(j); + int index = m_MemcardList[card]->InsertItem(j, wxEmptyString); m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); - if (!memoryCard[card]->DEntry_Comment1(j, title)) title[0]=0; - if (!memoryCard[card]->DEntry_Comment2(j, comment)) comment[0]=0; + if (!memoryCard[card]->DEntry_Comment1(fileIndex, title)) title[0]=0; + if (!memoryCard[card]->DEntry_Comment2(fileIndex, comment)) comment[0]=0; bool ascii = memoryCard[card]->IsAsciiEncoding(); @@ -721,14 +727,14 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxTitle); m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxComment); - blocks = memoryCard[card]->DEntry_BlockCount(j); + blocks = memoryCard[card]->DEntry_BlockCount(fileIndex); if (blocks == 0xFFFF) blocks = 0; wxBlock.Printf(wxT("%10d"), blocks); m_MemcardList[card]->SetItem(index,COLUMN_BLOCKS, wxBlock); - firstblock = memoryCard[card]->DEntry_FirstBlock(j); + firstblock = memoryCard[card]->DEntry_FirstBlock(fileIndex); if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 wxFirstBlock.Printf(wxT("%15d"), firstblock-4); - m_MemcardList[card]->SetItem(index,COLUMN_FIRSTBLOCK, wxFirstBlock); + m_MemcardList[card]->SetItem(index, COLUMN_FIRSTBLOCK, wxFirstBlock); m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); if (images[j] >= 0) From dfe890e8f11352f1ca91cca557a2788e2b102f4e Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Sat, 10 Dec 2011 15:44:08 -0800 Subject: [PATCH 03/10] pass by reference instead of pointer in several places, return std::strings instead of filling a buffer, move gci filename generation to a function inside gcmemcard instead of the gui code change all functions that do not modify the object to const Conflicts: Source/Core/Core/Src/HW/GCMemcard.cpp Source/Core/DolphinWX/Src/MemcardManager.cpp Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 253 +++++++++---------- Source/Core/Core/Src/HW/GCMemcard.h | 78 +++--- Source/Core/DolphinWX/Src/MemcardManager.cpp | 30 +-- 3 files changed, 173 insertions(+), 188 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 646c210b29..cd72a6826d 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -16,7 +16,6 @@ // http://code.google.com/p/dolphin-emu/ #include "GCMemcard.h" #include "ColorUtil.h" - static void ByteSwap(u8 *valueA, u8 *valueB) { u8 tmp = *valueA; @@ -225,7 +224,7 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) mcdFile.Close(); } -bool GCMemcard::IsAsciiEncoding() +bool GCMemcard::IsAsciiEncoding() const { return hdr.Encoding == 0; } @@ -267,7 +266,7 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum) } } -u32 GCMemcard::TestChecksums() +u32 GCMemcard::TestChecksums() const { u16 csum=0, csum_inv=0; @@ -306,7 +305,7 @@ bool GCMemcard::FixChecksums() return true; } -u8 GCMemcard::GetNumFiles() +u8 GCMemcard::GetNumFiles() const { if (!m_valid) return 0; @@ -320,13 +319,13 @@ u8 GCMemcard::GetNumFiles() return j; } -u8 GCMemcard::GetFileIndex(u8 fileNumber) +u8 GCMemcard::GetFileIndex(u8 fileNumber) const { if (m_valid) { u8 j = 0; - for (int i = 0; i < DIRLEN; i++) + for (u8 i = 0; i < DIRLEN; i++) { if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) { @@ -338,10 +337,10 @@ u8 GCMemcard::GetFileIndex(u8 fileNumber) } } } - return -1; + return 0xFF; } -u16 GCMemcard::GetFreeBlocks() +u16 GCMemcard::GetFreeBlocks() const { if (!m_valid) return 0; @@ -349,7 +348,7 @@ u16 GCMemcard::GetFreeBlocks() return BE16(bat.FreeBlocks); } -u8 GCMemcard::TitlePresent(DEntry d) +u8 GCMemcard::TitlePresent(DEntry d) const { if (!m_valid) return DIRLEN; @@ -367,102 +366,113 @@ u8 GCMemcard::TitlePresent(DEntry d) return i; } +bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const +{ + if (!m_valid || index > DIRLEN || (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF)) + return false; + filename = std::string((char*)dir.Dir[index].Gamecode, 4) + '_' + (char*)dir.Dir[index].Filename + ".gci"; + return true; +} // DEntry functions, all take u8 index < DIRLEN (127) // Functions that have ascii output take a char *buffer -bool GCMemcard::DEntry_GameCode(u8 index, char *buffer) +std::string GCMemcard::DEntry_GameCode(u8 index) const { - if (!m_valid) - return false; - - memcpy(buffer, dir.Dir[index].Gamecode, 4); - buffer[4] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)dir.Dir[index].Gamecode, 4); } -bool GCMemcard::DEntry_Markercode(u8 index, char *buffer) +std::string GCMemcard::DEntry_Makercode(u8 index) const { - if (!m_valid) - return false; - - memcpy(buffer, dir.Dir[index].Markercode, 2); - buffer[2] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)dir.Dir[index].Makercode, 2); } -bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer) -{ - if (!m_valid) - return false; +std::string GCMemcard::DEntry_BIFlags(u8 index) const +{ + if (!m_valid || index > DIRLEN) + return ""; + + std::string flags; int x = dir.Dir[index].BIFlags; for (int i = 0; i < 8; i++) { - buffer[i] = (x & 0x80) ? '1' : '0'; + flags.push_back((x & 0x80) ? '1' : '0'); x = x << 1; } - buffer[8] = 0; - return true; + flags.push_back(0); + return flags; } -bool GCMemcard::DEntry_FileName(u8 index, char *buffer) +std::string GCMemcard::DEntry_FileName(u8 index) const { - if (!m_valid) - return false; - - memcpy (buffer, (const char*)dir.Dir[index].Filename, DENTRY_STRLEN); - buffer[31] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)dir.Dir[index].Filename, DENTRY_STRLEN); } -u32 GCMemcard::DEntry_ModTime(u8 index) +u32 GCMemcard::DEntry_ModTime(u8 index) const { + if (!m_valid || index > DIRLEN) + return 0xFFFFFFFF; return BE32(dir.Dir[index].ModTime); } -u32 GCMemcard::DEntry_ImageOffset(u8 index) +u32 GCMemcard::DEntry_ImageOffset(u8 index) const { + if (!m_valid || index > DIRLEN) + return 0xFFFFFFFF; return BE32(dir.Dir[index].ImageOffset); } -bool GCMemcard::DEntry_IconFmt(u8 index, char *buffer) +std::string GCMemcard::DEntry_IconFmt(u8 index) const { - if (!m_valid) return false; - + if (!m_valid || index > DIRLEN) + return ""; int x = dir.Dir[index].IconFmt[0]; + std::string format; for(int i = 0; i < 16; i++) { if (i == 8) x = dir.Dir[index].IconFmt[1]; - buffer[i] = (x & 0x80) ? '1' : '0'; + format.push_back((x & 0x80) ? '1' : '0'); x = x << 1; } - buffer[16] = 0; - return true; - + format.push_back(0); + return format; } -u16 GCMemcard::DEntry_AnimSpeed(u8 index) +u16 GCMemcard::DEntry_AnimSpeed(u8 index) const { + if (!m_valid || index > DIRLEN) + return 0; return BE16(dir.Dir[index].AnimSpeed); } -bool GCMemcard::DEntry_Permissions(u8 index, char *fn) +std::string GCMemcard::DEntry_Permissions(u8 index) const { - if (!m_valid) return false; - fn[0] = (dir.Dir[index].Permissions & 16) ? 'x' : 'M'; - fn[1] = (dir.Dir[index].Permissions & 8) ? 'x' : 'C'; - fn[2] = (dir.Dir[index].Permissions & 4) ? 'P' : 'x'; - fn[3] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + u8 Permissions = dir.Dir[index].Permissions; + std::string permissionsString; + permissionsString.push_back((Permissions & 16) ? 'x' : 'M'); + permissionsString.push_back((Permissions & 8) ? 'x' : 'C'); + permissionsString.push_back((Permissions & 4) ? 'P' : 'x'); + permissionsString.push_back(0); + return permissionsString; } -u8 GCMemcard::DEntry_CopyCounter(u8 index) +u8 GCMemcard::DEntry_CopyCounter(u8 index) const { + if (!m_valid || index > DIRLEN) + return 0xFF; return dir.Dir[index].CopyCounter; } -u16 GCMemcard::DEntry_FirstBlock(u8 index) +u16 GCMemcard::DEntry_FirstBlock(u8 index) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return 0xFFFF; u16 block = BE16(dir.Dir[index].FirstBlock); @@ -470,9 +480,9 @@ u16 GCMemcard::DEntry_FirstBlock(u8 index) return block; } -u16 GCMemcard::DEntry_BlockCount(u8 index) +u16 GCMemcard::DEntry_BlockCount(u8 index) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return 0xFFFF; u16 blocks = BE16(dir.Dir[index].BlockCount); @@ -480,56 +490,51 @@ u16 GCMemcard::DEntry_BlockCount(u8 index) return blocks; } -u32 GCMemcard::DEntry_CommentsAddress(u8 index) +u32 GCMemcard::DEntry_CommentsAddress(u8 index) const { + if (!m_valid || index > DIRLEN) + return 0xFFFF; return BE32(dir.Dir[index].CommentsAddr); } -bool GCMemcard::DEntry_Comment1(u8 index, char* buffer) +std::string GCMemcard::GetSaveComment1(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { - buffer[0] = 0; - return false; + return ""; } - memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN); - buffer[31] = 0; - return true; + return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN); } -bool GCMemcard::DEntry_Comment2(u8 index, char* buffer) +std::string GCMemcard::GetSaveComment2(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); u32 Comment2 = Comment1 + DENTRY_STRLEN; u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { - buffer[0] = 0; - return false; + return ""; } - memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN); - buffer[31] = 0; - return true; + return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN); } -bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info) +bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return false; - - info = dir.Dir[index]; + dest = dir.Dir[index]; return true; } -u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) +u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) const { if (!m_valid) return NOMEMCARD; @@ -687,13 +692,13 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array while (nextIndex < DIRLEN) { - DEntry * tempDEntry = new DEntry; - DEntry_Copy(nextIndex, *tempDEntry); + DEntry tempDEntry; + GetDEntry(nextIndex, tempDEntry); u8 * tempSaveData = NULL; //Only get file data if it is a valid dir entry - if (BE16(tempDEntry->FirstBlock) != 0xFFFF) + if (BE16(tempDEntry.FirstBlock) != 0xFFFF) { - *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount)); + *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry.BlockCount)); u16 size = DEntry_BlockCount(nextIndex); if (size != 0xFFFF) @@ -707,7 +712,6 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array break; case FAIL: delete[] tempSaveData; - delete tempDEntry; return FAIL; } } @@ -716,10 +720,9 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array //Only call import file if DEntry_GetSaveData returns SUCCESS if (tempSaveData != NULL) { - ImportFile(*tempDEntry, tempSaveData, blocks_left); + ImportFile(tempDEntry, tempSaveData, blocks_left); delete[] tempSaveData; } - delete tempDEntry; nextIndex++; } @@ -737,13 +740,14 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array return SUCCESS; } -u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index) +u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) { - if (!m_valid) + if (!m_valid || !source.m_valid) return NOMEMCARD; DEntry tempDEntry; - if (!source.DEntry_Copy(index, tempDEntry)) return NOMEMCARD; + if (!source.GetDEntry(index, tempDEntry)) + return NOMEMCARD; u32 size = source.DEntry_BlockCount(index); if (size == 0xFFFF) return INVALIDFILESIZE; @@ -764,7 +768,7 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index) } } -u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile) +u32 GCMemcard::ImportGci(const char *inputFile, const std::string &outputFile) { if (outputFile.empty() && !m_valid) return OPENFAIL; @@ -778,7 +782,7 @@ u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile) return result; } -u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile) +u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile) { File::IOFile gci(gcih); unsigned int offset; @@ -810,8 +814,8 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string } gci.Seek(offset, SEEK_SET); - DEntry *tempDEntry = new DEntry; - gci.ReadBytes(tempDEntry, DENTRY_SIZE); + DEntry tempDEntry; + gci.ReadBytes(&tempDEntry, DENTRY_SIZE); const int fStart = (int)gci.Tell(); gci.Seek(0, SEEK_END); const int length = (int)gci.Tell() - fStart; @@ -819,12 +823,12 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string Gcs_SavConvert(tempDEntry, offset, length); - if (length != BE16(tempDEntry->BlockCount) * BLOCK_SIZE) + if (length != BE16(tempDEntry.BlockCount) * BLOCK_SIZE) return LENGTHFAIL; if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position return OPENFAIL; - u32 size = BE16((tempDEntry->BlockCount)) * BLOCK_SIZE; + u32 size = BE16((tempDEntry.BlockCount)) * BLOCK_SIZE; u8 *tempSaveData = new u8[size]; gci.ReadBytes(tempSaveData, size); u32 ret; @@ -835,14 +839,13 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string if (!gci2) { delete[] tempSaveData; - delete tempDEntry; return OPENFAIL; } gci2.Seek(0, SEEK_SET); - if (!gci2.WriteBytes(tempDEntry, DENTRY_SIZE)) + if (!gci2.WriteBytes(&tempDEntry, DENTRY_SIZE)) completeWrite = false; - int fileBlocks = BE16(tempDEntry->BlockCount); + int fileBlocks = BE16(tempDEntry.BlockCount); gci2.Seek(DENTRY_SIZE, SEEK_SET); if (!gci2.WriteBytes(tempSaveData, BLOCK_SIZE * fileBlocks)) @@ -853,14 +856,13 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string ret = WRITEFAIL; } else - ret = ImportFile(*tempDEntry, tempSaveData, 0); + ret = ImportFile(tempDEntry, tempSaveData, 0); delete[] tempSaveData; - delete tempDEntry; return ret; } -u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) +u32 GCMemcard::ExportGci(u8 index, const char* fileName, const std::string &directory) const { File::IOFile gci; int offset = GCI; @@ -868,15 +870,8 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) { if (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF) return SUCCESS; - size_t length = fileName2->length() + 42; - char *filename = new char[length]; - char GameCode[5]; - - DEntry_GameCode(index, GameCode); - - sprintf(filename, "%s/%s_%s.gci", fileName2->c_str(), GameCode, dir.Dir[index].Filename); - gci.Open(filename, "wb"); - delete[] filename; + std::string outpuName = directory + DIR_SEP + DEntry_GameCode(index) + '_' + (char*)dir.Dir[index].Filename + ".gci"; + gci.Open(outpuName, "wb"); } else { @@ -917,12 +912,12 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) } DEntry tempDEntry; - if (!DEntry_Copy(index, tempDEntry)) + if (!GetDEntry(index, tempDEntry)) { return NOMEMCARD; } - Gcs_SavConvert(&tempDEntry, offset); + Gcs_SavConvert(tempDEntry, offset); gci.WriteBytes(&tempDEntry, DENTRY_SIZE); u32 size = DEntry_BlockCount(index); @@ -955,7 +950,7 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) return WRITEFAIL; } -void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) +void GCMemcard::Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length) { switch(saveType) { @@ -965,7 +960,7 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) // 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" - *(u16*)&tempDEntry->BlockCount = BE16(length / BLOCK_SIZE); + *(u16*)&tempDEntry.BlockCount = BE16(length / BLOCK_SIZE); } break; case SAV: @@ -974,24 +969,24 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) // 0x34 and 0x35, 0x36 and 0x37, 0x38 and 0x39, 0x3A and 0x3B, // 0x3C and 0x3D,0x3E and 0x3F. // It seems that sav files also swap the BIFlags... - ByteSwap(&tempDEntry->Unused1, &tempDEntry->BIFlags); - ArrayByteSwap((tempDEntry->ImageOffset)); - ArrayByteSwap(&(tempDEntry->ImageOffset[2])); - ArrayByteSwap((tempDEntry->IconFmt)); - ArrayByteSwap((tempDEntry->AnimSpeed)); - ByteSwap(&tempDEntry->Permissions, &tempDEntry->CopyCounter); - ArrayByteSwap((tempDEntry->FirstBlock)); - ArrayByteSwap((tempDEntry->BlockCount)); - ArrayByteSwap((tempDEntry->Unused2)); - ArrayByteSwap((tempDEntry->CommentsAddr)); - ArrayByteSwap(&(tempDEntry->CommentsAddr[2])); + ByteSwap(&tempDEntry.Unused1, &tempDEntry.BIFlags); + ArrayByteSwap((tempDEntry.ImageOffset)); + ArrayByteSwap(&(tempDEntry.ImageOffset[2])); + ArrayByteSwap((tempDEntry.IconFmt)); + ArrayByteSwap((tempDEntry.AnimSpeed)); + ByteSwap(&tempDEntry.Permissions, &tempDEntry.CopyCounter); + ArrayByteSwap((tempDEntry.FirstBlock)); + ArrayByteSwap((tempDEntry.BlockCount)); + ArrayByteSwap((tempDEntry.Unused2)); + ArrayByteSwap((tempDEntry.CommentsAddr)); + ArrayByteSwap(&(tempDEntry.CommentsAddr[2])); break; default: break; } } -bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) +bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const { if (!m_valid) return false; @@ -1032,7 +1027,7 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) return true; } -u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) +u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const { if (!m_valid) return 0; diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index 59cecded32..57a42b9d3a 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -19,6 +19,7 @@ #define __GCMEMCARD_h__ #include "Common.h" +#include "CommonPaths.h" #include "Sram.h" #include "StringUtil.h" #include "EXI_DeviceIPL.h" @@ -101,7 +102,7 @@ private: struct DEntry { u8 Gamecode[4]; //0x00 0x04 Gamecode - u8 Markercode[2]; //0x04 0x02 Makercode + u8 Makercode[2]; //0x04 0x02 Makercode u8 Unused1; //0x06 0x01 reserved/unused (always 0xff, has no effect) u8 BIFlags; //0x07 0x01 banner gfx format and icon animation (Image Key) // bit(s) description @@ -168,67 +169,58 @@ private: }; #pragma pack(pop) - u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile); + u32 ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile); static void FormatInternal(GCMC_Header &GCP); public: GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false); - bool IsValid() { return m_valid; } - bool IsAsciiEncoding(); + bool IsValid() const { return m_valid; } + bool IsAsciiEncoding() const; bool Save(); bool Format(bool sjis = false, u16 SizeMb = MemCard2043Mb); static bool Format(u8 * card_data, bool sjis = false, u16 SizeMb = MemCard2043Mb); static void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum); - u32 TestChecksums(); + u32 TestChecksums() const; bool FixChecksums(); // get number of file entries in the directory - u8 GetNumFiles(); - u8 GetFileIndex(u8 fileNumber); + u8 GetNumFiles() const; + u8 GetFileIndex(u8 fileNumber) const; // get the free blocks from bat - u16 GetFreeBlocks(); + u16 GetFreeBlocks() const; // If title already on memcard returns index, otherwise returns -1 - u8 TitlePresent(DEntry d); - - // DEntry functions, all take u8 index < DIRLEN (127) - // Functions that have ascii output take a char *buffer + u8 TitlePresent(DEntry d) const; - // buffer needs to be a char[5] or bigger - bool DEntry_GameCode(u8 index, char *buffer); - // buffer needs to be a char[2] or bigger - bool DEntry_Markercode(u8 index, char *buffer); - // buffer needs to be a char[9] or bigger - bool DEntry_BIFlags(u8 index, char *buffer); - // buffer needs to be a char[32] or bigger - bool DEntry_FileName(u8 index, char *buffer); - u32 DEntry_ModTime(u8 index); - u32 DEntry_ImageOffset(u8 index); - // buffer needs to be a char[17] or bigger - bool DEntry_IconFmt(u8 index, char *buffer); - u16 DEntry_AnimSpeed(u8 index); - // buffer needs to be a char[4] or bigger - bool DEntry_Permissions(u8 index, char *buffer); - u8 DEntry_CopyCounter(u8 index); + bool GCI_FileName(u8 index, std::string &filename) const; + // DEntry functions, all take u8 index < DIRLEN (127) + std::string DEntry_GameCode(u8 index) const; + std::string DEntry_Makercode(u8 index) const; + std::string DEntry_BIFlags(u8 index) const; + std::string DEntry_FileName(u8 index) const; + u32 DEntry_ModTime(u8 index) const; + u32 DEntry_ImageOffset(u8 index) const; + std::string DEntry_IconFmt(u8 index) const; + u16 DEntry_AnimSpeed(u8 index) const; + std::string DEntry_Permissions(u8 index) const; + u8 DEntry_CopyCounter(u8 index) const; // get first block for file - u16 DEntry_FirstBlock(u8 index); + u16 DEntry_FirstBlock(u8 index) const; // get file length in blocks - u16 DEntry_BlockCount(u8 index); - u32 DEntry_CommentsAddress(u8 index); - // buffer needs to be a char[32] or bigger - bool DEntry_Comment1(u8 index, char *buffer); - // buffer needs to be a char[32] or bigger - bool DEntry_Comment2(u8 index, char *buffer); + u16 DEntry_BlockCount(u8 index) const; + u32 DEntry_CommentsAddress(u8 index) const; + std::string GetSaveComment1(u8 index) const; + std::string GetSaveComment2(u8 index) const; // Copies a DEntry from u8 index to DEntry& data - bool DEntry_Copy(u8 index, DEntry& data); + bool GetDEntry(u8 index, DEntry &dest) const; // assumes there's enough space in 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 - u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old); + u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old) const; // adds the file to the directory and copies its contents // if remove > 0 it will pad bat.map with 0's sizeof remove @@ -238,23 +230,23 @@ public: u32 RemoveFile(u8 index); // reads a save from another memcard, and imports the data into this memcard - u32 CopyFrom(GCMemcard& source, u8 index); + u32 CopyFrom(const GCMemcard& source, u8 index); // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file - u32 ImportGci(const char* inputFile, std::string outputFile); + u32 ImportGci(const char* inputFile,const std::string &outputFile); // writes a .gci file to disk containing index - u32 ExportGci(u8 index, const char* fileName, std::string* fileName2); + u32 ExportGci(u8 index, const char* fileName, const std::string &directory) const; // GCI files are untouched, SAV files are byteswapped // GCS files have the block count set, default is 1 (For export as GCS) - void Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length = BLOCK_SIZE); + static void Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length = BLOCK_SIZE); // reads the banner image - bool ReadBannerRGBA8(u8 index, u32* buffer); + bool ReadBannerRGBA8(u8 index, u32* buffer) const; // reads the animation frames - u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays); + u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const; }; #endif diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index a7b999f7a6..84e6eb8b1d 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -546,15 +546,16 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) index = memoryCard[slot]->GetFileIndex(index); if (index != wxNOT_FOUND) { - char tempC[10 + DENTRY_STRLEN], - tempC2[DENTRY_STRLEN]; - memoryCard[slot]->DEntry_GameCode(index,tempC); - memoryCard[slot]->DEntry_FileName(index,tempC2); - sprintf(tempC, "%s_%s.gci", tempC, tempC2); + std::string gciFilename; + if (!memoryCard[slot]->GCI_FileName(index, gciFilename)) + { + PanicAlert("invalid index"); + return; + } wxString fileName = wxFileSelector( _("Export save as..."), wxString::From8BitData(DefaultIOPath.c_str()), - wxString::From8BitData(tempC), wxT(".gci"), + wxString::From8BitData(gciFilename.c_str()), wxT(".gci"), _("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) + _("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) + _("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")), @@ -562,7 +563,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) if (fileName.length() > 0) { - if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, fileName.mb_str(), NULL), -1)) + if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, fileName.mb_str(), ""), -1)) { File::Delete(std::string(fileName.mb_str())); } @@ -582,7 +583,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) "%s\nand have the same name as a file on your memcard\nContinue?", path1.c_str())) for (int i = 0; i < DIRLEN; i++) { - CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, ".", &path1), -1); + CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, NULL, path1), -1); } break; } @@ -614,8 +615,7 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) wxComment, wxBlock, wxFirstBlock, - wxLabel, - tString; + wxLabel; m_MemcardList[card]->Hide(); @@ -689,8 +689,6 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) for (j = page[card] * itemsPerPage; (j < nFiles) && (j < pagesMax); j++) { - char title[DENTRY_STRLEN]; - char comment[DENTRY_STRLEN]; u16 blocks; u16 firstblock; u8 fileIndex = memoryCard[card]->GetFileIndex(j); @@ -700,8 +698,8 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); - if (!memoryCard[card]->DEntry_Comment1(fileIndex, title)) title[0]=0; - if (!memoryCard[card]->DEntry_Comment2(fileIndex, comment)) comment[0]=0; + std::string title = memoryCard[card]->GetSaveComment1(fileIndex); + std::string comment = memoryCard[card]->GetSaveComment2(fileIndex); bool ascii = memoryCard[card]->IsAsciiEncoding(); @@ -721,8 +719,8 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) // it returns CP-932, in order to use iconv we need to use CP932 wxCSConv SJISConv(wxT("CP932")); #endif - wxTitle = wxString(title, ascii ? *wxConvCurrent : SJISConv); - wxComment = wxString(comment, ascii ? *wxConvCurrent : SJISConv); + wxTitle = wxString(title.c_str(), ascii ? *wxConvCurrent : SJISConv); + wxComment = wxString(comment.c_str(), ascii ? *wxConvCurrent : SJISConv); m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxTitle); m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxComment); From 8355363dcd4783eea852768e2007d8c29c069fef Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Sat, 10 Dec 2011 15:44:40 -0800 Subject: [PATCH 04/10] change the data section from a plain array to a vector of blocks (arrays of 0x2000) Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 171 ++++++++++++-------------- Source/Core/Core/Src/HW/GCMemcard.h | 15 ++- 2 files changed, 91 insertions(+), 95 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index cd72a6826d..7a574b7106 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -63,7 +63,6 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height) GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_valid(false) , m_fileName(filename) - , mc_data(NULL) { File::IOFile mcdFile(m_fileName, "r+b"); if (!mcdFile.IsOpen()) @@ -209,16 +208,22 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) mcdFile.Seek(0xa000, SEEK_SET); maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE; - mc_data = new u8[mc_data_size]; - - if (mcdFile.ReadBytes(mc_data, mc_data_size)) + mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); + + m_valid = true; + for (u32 i = MC_FST_BLOCKS; i < maxBlock; ++i) { - m_valid = true; - } - else - { - PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated"); + GCMBlock b; + if (mcdFile.ReadBytes(b.block, BLOCK_SIZE)) + { + mc_data_blocks.push_back(b); + } + else + { + PanicAlertT("Failed to read block %d of the save data\nMemcard may be truncated\nFilePosition:%llx", i, mcdFile.Tell()); + m_valid = false; + break; + } } mcdFile.Close(); @@ -239,7 +244,10 @@ bool GCMemcard::Save() mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); mcdFile.WriteBytes(&bat, BLOCK_SIZE); mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); - mcdFile.WriteBytes(mc_data, mc_data_size); + for (int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) + { + mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE); + } return mcdFile.Close(); } @@ -373,6 +381,7 @@ bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const filename = std::string((char*)dir.Dir[index].Gamecode, 4) + '_' + (char*)dir.Dir[index].Filename + ".gci"; return true; } + // DEntry functions, all take u8 index < DIRLEN (127) // Functions that have ascii output take a char *buffer @@ -446,7 +455,7 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const u16 GCMemcard::DEntry_AnimSpeed(u8 index) const { if (!m_valid || index > DIRLEN) - return 0; + return 0xFF; return BE16(dir.Dir[index].AnimSpeed); } @@ -508,7 +517,7 @@ std::string GCMemcard::GetSaveComment1(u8 index) const { return ""; } - return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN); + return std::string((const char *)mc_data_blocks[DataBlock].block + Comment1, DENTRY_STRLEN); } std::string GCMemcard::GetSaveComment2(u8 index) const @@ -523,7 +532,7 @@ std::string GCMemcard::GetSaveComment2(u8 index) const { return ""; } - return std::string((const char *)mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN); + return std::string((const char *)mc_data_blocks[DataBlock].block + Comment2, DENTRY_STRLEN); } bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const @@ -534,7 +543,7 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const return true; } -u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) const +u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const { if (!m_valid) return NOMEMCARD; @@ -549,31 +558,15 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) const return FAIL; } - if (!old) + for (int i = 0; i < saveLength; ++i) { - memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), saveLength * BLOCK_SIZE); - } - else - { - if (block == 0) return FAIL; - while (block != 0xffff) - { - memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), BLOCK_SIZE); - dest += BLOCK_SIZE; - - u16 nextblock = Common::swap16(bat.Map[block - MC_FST_BLOCKS]); - if (block + saveLength != memcardSize && nextblock > 0) - {//Fixes for older memcards that were not initialized with FF - block = nextblock; - } - else break; - } + Blocks.push_back(mc_data_blocks[i + block-MC_FST_BLOCKS]); } return SUCCESS; } // End DEntry functions -u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) +u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, int remove) { if (!m_valid) return NOMEMCARD; @@ -627,11 +620,15 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) } } - // keep assuming no freespace fragmentation, and copy over all the data - u8 *destination = mc_data + (firstFree1 - MC_FST_BLOCKS) * BLOCK_SIZE; int fileBlocks = BE16(direntry.BlockCount); - memcpy(destination, contents, BLOCK_SIZE * fileBlocks); + firstFree1 -= MC_FST_BLOCKS; + // keep assuming no freespace fragmentation, and copy over all the data + for (int i = 0; i < fileBlocks; ++i) + { + mc_data_blocks[i + firstFree1] = saveBlocks[i]; + } + bat_backup = bat; u16 last = BE16(bat_backup.LastAllocated); u16 i = (last - 4); @@ -694,34 +691,31 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array { DEntry tempDEntry; GetDEntry(nextIndex, tempDEntry); - u8 * tempSaveData = NULL; + std::vector saveData; + u16 size = 0; //Only get file data if it is a valid dir entry if (BE16(tempDEntry.FirstBlock) != 0xFFFF) { *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry.BlockCount)); - u16 size = DEntry_BlockCount(nextIndex); + size = DEntry_BlockCount(nextIndex); if (size != 0xFFFF) { - tempSaveData = new u8[size * BLOCK_SIZE]; - switch (DEntry_GetSaveData(nextIndex, tempSaveData, true)) + saveData.reserve(size); + switch (GetSaveData(nextIndex, saveData)) { case NOMEMCARD: - delete[] tempSaveData; - tempSaveData = NULL; break; case FAIL: - delete[] tempSaveData; return FAIL; } } } memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE); - //Only call import file if DEntry_GetSaveData returns SUCCESS - if (tempSaveData != NULL) + //Only call import file if GetSaveData returns SUCCESS + if (saveData.size() == size) { - ImportFile(tempDEntry, tempSaveData, blocks_left); - delete[] tempSaveData; + ImportFile(tempDEntry, saveData, blocks_left); } nextIndex++; @@ -751,20 +745,17 @@ u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) u32 size = source.DEntry_BlockCount(index); if (size == 0xFFFF) return INVALIDFILESIZE; - u8 *tempSaveData = new u8[size * BLOCK_SIZE]; - switch (source.DEntry_GetSaveData(index, tempSaveData, true)) + std::vector saveData; + saveData.reserve(size); + switch (source.GetSaveData(index, saveData)) { case FAIL: - delete[] tempSaveData; return FAIL; case NOMEMCARD: - delete[] tempSaveData; return NOMEMCARD; default: - u32 ret = ImportFile(tempDEntry, tempSaveData, 0); - delete[] tempSaveData; - return ret; + return ImportFile(tempDEntry, saveData, 0); } } @@ -828,9 +819,16 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position return OPENFAIL; - u32 size = BE16((tempDEntry.BlockCount)) * BLOCK_SIZE; - u8 *tempSaveData = new u8[size]; - gci.ReadBytes(tempSaveData, size); + u32 size = BE16((tempDEntry.BlockCount)); + std::vector saveData; + saveData.reserve(size); + + for (int i = 0; i < size; ++i) + { + GCMBlock b; + gci.ReadBytes(b.block, BLOCK_SIZE); + saveData.push_back(b); + } u32 ret; if (!outputFile.empty()) { @@ -838,7 +836,6 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s bool completeWrite = true; if (!gci2) { - delete[] tempSaveData; return OPENFAIL; } gci2.Seek(0, SEEK_SET); @@ -848,30 +845,32 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s int fileBlocks = BE16(tempDEntry.BlockCount); gci2.Seek(DENTRY_SIZE, SEEK_SET); - if (!gci2.WriteBytes(tempSaveData, BLOCK_SIZE * fileBlocks)) + for (int i = 0; i < fileBlocks; ++i) + { + if (!gci2.WriteBytes(saveData[i].block, BLOCK_SIZE)) completeWrite = false; + } + if (completeWrite) ret = GCS; else ret = WRITEFAIL; } else - ret = ImportFile(tempDEntry, tempSaveData, 0); + ret = ImportFile(tempDEntry, saveData, 0); - delete[] tempSaveData; return ret; } -u32 GCMemcard::ExportGci(u8 index, const char* fileName, const std::string &directory) const +u32 GCMemcard::ExportGci(u8 index, const char *fileName, const std::string &directory) const { File::IOFile gci; int offset = GCI; - if (!strcasecmp(fileName, ".")) + if (!fileName) { - if (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF) return SUCCESS; - - std::string outpuName = directory + DIR_SEP + DEntry_GameCode(index) + '_' + (char*)dir.Dir[index].Filename + ".gci"; - gci.Open(outpuName, "wb"); + std::string gciFilename; + if (!GCI_FileName(index, gciFilename)) return SUCCESS; + gci.Open(directory + DIR_SEP + gciFilename, "wb"); } else { @@ -926,23 +925,21 @@ u32 GCMemcard::ExportGci(u8 index, const char* fileName, const std::string &dire return FAIL; } - size *= BLOCK_SIZE; - u8 *tempSaveData = new u8[size]; + std::vector saveData; + saveData.reserve(size); - switch(DEntry_GetSaveData(index, tempSaveData, true)) + switch(GetSaveData(index, saveData)) { case FAIL: - delete[] tempSaveData; return FAIL; - case NOMEMCARD: - delete[] tempSaveData; return NOMEMCARD; } gci.Seek(DENTRY_SIZE + offset, SEEK_SET); - gci.WriteBytes(tempSaveData, size); - - delete[] tempSaveData; + for (int i = 0; i < size; ++i) + { + gci.WriteBytes(saveData[i].block, BLOCK_SIZE); + } if (gci.IsGood()) return SUCCESS; @@ -1013,14 +1010,14 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const if (bnrFormat&1) { - u8 *pxdata = (u8* )(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); - u16 *paldata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset + pixels); + u8 *pxdata = (u8* )(mc_data_blocks[DataBlock].block + DataOffset); + u16 *paldata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset + pixels); decodeCI8image(buffer, pxdata, paldata, 96, 32); } else { - u16 *pxdata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); + u16 *pxdata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset); decode5A3image(buffer, pxdata, 96, 32); } @@ -1053,7 +1050,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const return 0; } - u8* animData = (u8*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); + u8* animData = (u8*)(mc_data_blocks[DataBlock].block + DataOffset); switch (bnrFormat) { @@ -1169,17 +1166,13 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb) m_sizeMb = SizeMb; maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - if (mc_data) + mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); + for (u32 i = 0; i < (maxBlock - MC_FST_BLOCKS); ++i) { - delete mc_data; - mc_data = NULL; + GCMBlock b; + mc_data_blocks.push_back(b); } - mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS); - mc_data = new u8[mc_data_size]; - if (!mc_data) - return false; - memset(mc_data, 0xFF, mc_data_size); m_valid = true; return Save(); diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index 57a42b9d3a..e1ab970053 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -76,11 +76,14 @@ private: std::string m_fileName; u32 maxBlock; - u32 mc_data_size; - u8* mc_data; - u16 m_sizeMb; - + struct GCMBlock + { + GCMBlock(){erase();} + void erase() {memset(block, 0xFF, BLOCK_SIZE);} + u8 block[BLOCK_SIZE]; + }; + std::vector mc_data_blocks; #pragma pack(push,1) struct Header { //Offset Size Description // Serial in libogc @@ -220,11 +223,11 @@ public: // 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 - u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old) const; + u32 GetSaveData(u8 index, std::vector &saveBlocks) const; // adds the file to the directory and copies its contents // if remove > 0 it will pad bat.map with 0's sizeof remove - u32 ImportFile(DEntry& direntry, u8* contents, int remove); + u32 ImportFile(DEntry& direntry, std::vector &saveBlocks, int remove); // delete a file from the directory u32 RemoveFile(u8 index); From 1fe67e19ab8ee1dfb87df3d348270bd76eb5a9b5 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 01:52:13 -0800 Subject: [PATCH 05/10] use BAT for block locations instead of assuming nonfragmented blocks *untested* Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 105 +++++++++++++++++++++----- Source/Core/Core/Src/HW/GCMemcard.h | 6 +- 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 7a574b7106..2926017b2a 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -543,24 +543,61 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const return true; } +u16 GCMemcard::GetNextBlock(u16 Block) const +{ + if ((Block < MC_FST_BLOCKS) || (Block > maxBlock)) + return 0; + return Common::swap16(bat.Map[Block-MC_FST_BLOCKS]); +} + +u16 GCMemcard::NextFreeBlock(u16 StartingBlock) const +{ + for (u16 i = StartingBlock; i < BAT_SIZE; ++i) + if (bat.Map[i-MC_FST_BLOCKS] == 0) + return i; +} + +bool GCMemcard::ClearBlocks(u16 FirstBlock, u16 BlockCount) +{ + std::vector blocks; + while (FirstBlock != 0xFF && FirstBlock != 0) + { + blocks.push_back(FirstBlock); + FirstBlock = GetNextBlock(FirstBlock); + } + + if (FirstBlock > 0) + { + size_t length = blocks.size(); + if (length != BlockCount) + return false; + for (int i = 0; i < length; ++i) + bat.Map[blocks.at(i)-MC_FST_BLOCKS] = 0; + *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BlockCount); + } + return true; +} u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const { if (!m_valid) return NOMEMCARD; u16 block = DEntry_FirstBlock(index); - u16 saveLength = DEntry_BlockCount(index); + u16 BlockCount = DEntry_BlockCount(index); u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; - if ((block == 0xFFFF) || (saveLength == 0xFFFF) - || (block + saveLength > memcardSize)) + if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) { return FAIL; } - for (int i = 0; i < saveLength; ++i) + u16 nextBlock = block; + for (int i = 0; i < BlockCount; ++i) { - Blocks.push_back(mc_data_blocks[i + block-MC_FST_BLOCKS]); + if ((!nextBlock) || (nextBlock == 0xFFFF)) + return FAIL; + Blocks.push_back(mc_data_blocks[nextBlock-MC_FST_BLOCKS]); + nextBlock = GetNextBlock(nextBlock); } return SUCCESS; } @@ -585,10 +622,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i } // find first free data block -- assume no freespace fragmentation - int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - int firstFree1 = BE16(bat.LastAllocated) + 1; - int firstFree2 = 0; - for (int i = 0; i < DIRLEN; i++) + //int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); + //int firstFree1 = BE16(bat.LastAllocated) + 1; + + + +/* for (int i = 0; i < DIRLEN; i++) { if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) { @@ -601,7 +640,8 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i } } firstFree1 = max(firstFree1, firstFree2); - + */ + u16 firstBlock = NextFreeBlock(); // find first free dir entry int index = -1; for (int i=0; i < DIRLEN; i++) @@ -610,7 +650,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i { index = i; dir.Dir[i] = direntry; - *(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1); + *(u16*)&dir.Dir[i].FirstBlock = BE16(firstBlock); if (!remove) { dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; @@ -622,15 +662,22 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i int fileBlocks = BE16(direntry.BlockCount); - firstFree1 -= MC_FST_BLOCKS; + + u16 nextBlock; // keep assuming no freespace fragmentation, and copy over all the data for (int i = 0; i < fileBlocks; ++i) - { - mc_data_blocks[i + firstFree1] = saveBlocks[i]; + { + mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; + if (i == fileBlocks-1) + nextBlock = 0xFFFF; + else + nextBlock = NextFreeBlock(firstBlock+1); + bat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + firstBlock = nextBlock; } bat_backup = bat; - u16 last = BE16(bat_backup.LastAllocated); +/* u16 last = BE16(bat_backup.LastAllocated); u16 i = (last - 4); int j = 2; while(j < BE16(direntry.BlockCount) + 1) @@ -645,11 +692,12 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i { bat_backup.Map[i++] = 0x0000; } - + */ //update last allocated block - *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); +/* *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); +*/ //update freespace counter - *(u16*)&bat_backup.FreeBlocks = BE16(totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS); + *(u16*)&bat_backup.FreeBlocks = BE16(BE16(bat_backup.FreeBlocks) - fileBlocks); if (!remove) @@ -666,7 +714,25 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array { if (!m_valid) return NOMEMCARD; + if (index >= DIRLEN) + return DELETE_FAIL; + + dir_backup = dir; + bat_backup = bat; + u16 startingblock = BE16(dir.Dir[index].FirstBlock); + u16 numberofblocks = BE16(dir.Dir[index].BlockCount); + if (!ClearBlocks(startingblock, numberofblocks)) + return DELETE_FAIL; + + + memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE); + + *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); + *(u16*)&bat.UpdateCounter = BE16(BE16(bat.UpdateCounter) + 1); + + return SUCCESS; + /* //error checking u16 startingblock = 0; for (int i = 0; i < DIRLEN; i++) @@ -730,8 +796,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array } // increment update counter *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); - - return SUCCESS; + */ } u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index e1ab970053..e66f77887e 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -55,6 +55,7 @@ enum DENTRY_STRLEN = 0x20, DENTRY_SIZE = 0x40, BLOCK_SIZE = 0x2000, + BAT_SIZE = 0xFFB, MemCard59Mb = 0x04, MemCard123Mb = 0x08, @@ -162,7 +163,7 @@ private: u8 UpdateCounter[2];//0x0004 2 update Counter u8 FreeBlocks[2]; //0x0006 2 free Blocks u8 LastAllocated[2];//0x0008 2 last allocated Block - u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks + u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks } bat,bat_backup; struct GCMC_Header { @@ -218,6 +219,9 @@ public: std::string GetSaveComment2(u8 index) const; // Copies a DEntry from u8 index to DEntry& data bool GetDEntry(u8 index, DEntry &dest) const; + u16 GetNextBlock(u16 Block) const; + u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; + bool ClearBlocks(u16 StartingBlock, u16 Length); // assumes there's enough space in buffer // old determines if function uses old or new method of copying data From 3d20c5745896f0787ed0d974e73d20f11d240de9 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 17:27:49 -0800 Subject: [PATCH 06/10] Update directorys and BlockAllocs correctly, use the most uptodate directory/bat instead of always the first Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 335 +++++++++---------- Source/Core/Core/Src/HW/GCMemcard.h | 12 +- Source/Core/DolphinWX/Src/MemcardManager.cpp | 4 +- 3 files changed, 164 insertions(+), 187 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 2926017b2a..9b9d39fc02 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -227,6 +227,28 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) } mcdFile.Close(); + + if (BE16(dir.UpdateCounter) > (BE16(dir_backup.UpdateCounter))) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + if (BE16(bat.UpdateCounter) > BE16(bat_backup.UpdateCounter)) + { + PanicAlert("jere, %x, %x",BE16(bat.UpdateCounter) , BE16(bat_backup.UpdateCounter)); + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; + } } bool GCMemcard::IsAsciiEncoding() const @@ -321,7 +343,7 @@ u8 GCMemcard::GetNumFiles() const u8 j = 0; for (int i = 0; i < DIRLEN; i++) { - if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) + if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) j++; } return j; @@ -335,7 +357,7 @@ u8 GCMemcard::GetFileIndex(u8 fileNumber) const u8 j = 0; for (u8 i = 0; i < DIRLEN; i++) { - if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) + if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) { if (j == fileNumber) { @@ -353,7 +375,7 @@ u16 GCMemcard::GetFreeBlocks() const if (!m_valid) return 0; - return BE16(bat.FreeBlocks); + return BE16(CurrentBat->FreeBlocks); } u8 GCMemcard::TitlePresent(DEntry d) const @@ -364,8 +386,8 @@ u8 GCMemcard::TitlePresent(DEntry d) const u8 i = 0; while(i < DIRLEN) { - if ((BE32(dir.Dir[i].Gamecode) == BE32(d.Gamecode)) && - (!memcmp(dir.Dir[i].Filename, d.Filename, 32))) + if ((BE32(CurrentDir->Dir[i].Gamecode) == BE32(d.Gamecode)) && + (!memcmp(CurrentDir->Dir[i].Filename, d.Filename, 32))) { break; } @@ -376,9 +398,9 @@ u8 GCMemcard::TitlePresent(DEntry d) const bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const { - if (!m_valid || index > DIRLEN || (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF)) + if (!m_valid || index > DIRLEN || (BE32(CurrentDir->Dir[index].Gamecode) == 0xFFFFFFFF)) return false; - filename = std::string((char*)dir.Dir[index].Gamecode, 4) + '_' + (char*)dir.Dir[index].Filename + ".gci"; + filename = std::string((char*)CurrentDir->Dir[index].Gamecode, 4) + '_' + (char*)CurrentDir->Dir[index].Filename + ".gci"; return true; } @@ -389,14 +411,14 @@ std::string GCMemcard::DEntry_GameCode(u8 index) const { if (!m_valid || index > DIRLEN) return ""; - return std::string((const char*)dir.Dir[index].Gamecode, 4); + return std::string((const char*)CurrentDir->Dir[index].Gamecode, 4); } std::string GCMemcard::DEntry_Makercode(u8 index) const { if (!m_valid || index > DIRLEN) return ""; - return std::string((const char*)dir.Dir[index].Makercode, 2); + return std::string((const char*)CurrentDir->Dir[index].Makercode, 2); } std::string GCMemcard::DEntry_BIFlags(u8 index) const @@ -405,7 +427,7 @@ std::string GCMemcard::DEntry_BIFlags(u8 index) const return ""; std::string flags; - int x = dir.Dir[index].BIFlags; + int x = CurrentDir->Dir[index].BIFlags; for (int i = 0; i < 8; i++) { flags.push_back((x & 0x80) ? '1' : '0'); @@ -419,32 +441,32 @@ std::string GCMemcard::DEntry_FileName(u8 index) const { if (!m_valid || index > DIRLEN) return ""; - return std::string((const char*)dir.Dir[index].Filename, DENTRY_STRLEN); + return std::string((const char*)CurrentDir->Dir[index].Filename, DENTRY_STRLEN); } u32 GCMemcard::DEntry_ModTime(u8 index) const { if (!m_valid || index > DIRLEN) return 0xFFFFFFFF; - return BE32(dir.Dir[index].ModTime); + return BE32(CurrentDir->Dir[index].ModTime); } u32 GCMemcard::DEntry_ImageOffset(u8 index) const { if (!m_valid || index > DIRLEN) return 0xFFFFFFFF; - return BE32(dir.Dir[index].ImageOffset); + return BE32(CurrentDir->Dir[index].ImageOffset); } std::string GCMemcard::DEntry_IconFmt(u8 index) const { if (!m_valid || index > DIRLEN) return ""; - int x = dir.Dir[index].IconFmt[0]; + int x = CurrentDir->Dir[index].IconFmt[0]; std::string format; for(int i = 0; i < 16; i++) { - if (i == 8) x = dir.Dir[index].IconFmt[1]; + if (i == 8) x = CurrentDir->Dir[index].IconFmt[1]; format.push_back((x & 0x80) ? '1' : '0'); x = x << 1; } @@ -456,14 +478,14 @@ u16 GCMemcard::DEntry_AnimSpeed(u8 index) const { if (!m_valid || index > DIRLEN) return 0xFF; - return BE16(dir.Dir[index].AnimSpeed); + return BE16(CurrentDir->Dir[index].AnimSpeed); } std::string GCMemcard::DEntry_Permissions(u8 index) const { if (!m_valid || index > DIRLEN) return ""; - u8 Permissions = dir.Dir[index].Permissions; + u8 Permissions = CurrentDir->Dir[index].Permissions; std::string permissionsString; permissionsString.push_back((Permissions & 16) ? 'x' : 'M'); permissionsString.push_back((Permissions & 8) ? 'x' : 'C'); @@ -476,7 +498,7 @@ u8 GCMemcard::DEntry_CopyCounter(u8 index) const { if (!m_valid || index > DIRLEN) return 0xFF; - return dir.Dir[index].CopyCounter; + return CurrentDir->Dir[index].CopyCounter; } u16 GCMemcard::DEntry_FirstBlock(u8 index) const @@ -484,7 +506,7 @@ u16 GCMemcard::DEntry_FirstBlock(u8 index) const if (!m_valid || index > DIRLEN) return 0xFFFF; - u16 block = BE16(dir.Dir[index].FirstBlock); + u16 block = BE16(CurrentDir->Dir[index].FirstBlock); if (block > (u16) maxBlock) return 0xFFFF; return block; } @@ -494,7 +516,7 @@ u16 GCMemcard::DEntry_BlockCount(u8 index) const if (!m_valid || index > DIRLEN) return 0xFFFF; - u16 blocks = BE16(dir.Dir[index].BlockCount); + u16 blocks = BE16(CurrentDir->Dir[index].BlockCount); if (blocks > (u16) maxBlock) return 0xFFFF; return blocks; } @@ -503,7 +525,7 @@ u32 GCMemcard::DEntry_CommentsAddress(u8 index) const { if (!m_valid || index > DIRLEN) return 0xFFFF; - return BE32(dir.Dir[index].CommentsAddr); + return BE32(CurrentDir->Dir[index].CommentsAddr); } std::string GCMemcard::GetSaveComment1(u8 index) const @@ -511,8 +533,8 @@ std::string GCMemcard::GetSaveComment1(u8 index) const if (!m_valid || index > DIRLEN) return ""; - u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { return ""; @@ -525,9 +547,9 @@ std::string GCMemcard::GetSaveComment2(u8 index) const if (!m_valid || index > DIRLEN) return ""; - u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); u32 Comment2 = Comment1 + DENTRY_STRLEN; - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { return ""; @@ -539,44 +561,47 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const { if (!m_valid || index > DIRLEN) return false; - dest = dir.Dir[index]; + dest = CurrentDir->Dir[index]; return true; } - -u16 GCMemcard::GetNextBlock(u16 Block) const +u16 GCMemcard::BlockAlloc::GetNextBlock(u16 Block) const { - if ((Block < MC_FST_BLOCKS) || (Block > maxBlock)) + if ((Block < MC_FST_BLOCKS) || (Block > 4091)) return 0; - return Common::swap16(bat.Map[Block-MC_FST_BLOCKS]); + return Common::swap16(Map[Block-MC_FST_BLOCKS]); } -u16 GCMemcard::NextFreeBlock(u16 StartingBlock) const +u16 GCMemcard::BlockAlloc::NextFreeBlock(u16 StartingBlock) const { for (u16 i = StartingBlock; i < BAT_SIZE; ++i) - if (bat.Map[i-MC_FST_BLOCKS] == 0) + if (Map[i-MC_FST_BLOCKS] == 0) return i; } -bool GCMemcard::ClearBlocks(u16 FirstBlock, u16 BlockCount) +bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) { std::vector blocks; - while (FirstBlock != 0xFF && FirstBlock != 0) + while (FirstBlock != 0xFFFF && FirstBlock != 0) { blocks.push_back(FirstBlock); FirstBlock = GetNextBlock(FirstBlock); } - if (FirstBlock > 0) { size_t length = blocks.size(); if (length != BlockCount) + { return false; + } for (int i = 0; i < length; ++i) - bat.Map[blocks.at(i)-MC_FST_BLOCKS] = 0; - *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BlockCount); + Map[blocks.at(i)-MC_FST_BLOCKS] = 0; + *(u16*)&FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); + + return true; } - return true; + return false; } + u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const { if (!m_valid) @@ -597,13 +622,13 @@ u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const if ((!nextBlock) || (nextBlock == 0xFFFF)) return FAIL; Blocks.push_back(mc_data_blocks[nextBlock-MC_FST_BLOCKS]); - nextBlock = GetNextBlock(nextBlock); + nextBlock = CurrentBat->GetNextBlock(nextBlock); } return SUCCESS; } // End DEntry functions -u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, int remove) +u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) { if (!m_valid) return NOMEMCARD; @@ -612,11 +637,11 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i { return OUTOFDIRENTRIES; } - if (BE16(bat.FreeBlocks) < BE16(direntry.BlockCount)) + if (BE16(CurrentBat->FreeBlocks) < BE16(direntry.BlockCount)) { return OUTOFBLOCKS; } - if (!remove && (TitlePresent(direntry) != DIRLEN)) + if (TitlePresent(direntry) != DIRLEN) { return TITLEPRESENT; } @@ -625,44 +650,40 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i //int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); //int firstFree1 = BE16(bat.LastAllocated) + 1; + u16 firstBlock = CurrentBat->NextFreeBlock(); + Directory UpdatedDir = *CurrentDir; -/* for (int i = 0; i < DIRLEN; i++) - { - if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) - { - break; - } - else - { - firstFree2 = max(firstFree2, - (int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount))); - } - } - firstFree1 = max(firstFree1, firstFree2); - */ - u16 firstBlock = NextFreeBlock(); // find first free dir entry int index = -1; for (int i=0; i < DIRLEN; i++) { - if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) + if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF) { index = i; - dir.Dir[i] = direntry; - *(u16*)&dir.Dir[i].FirstBlock = BE16(firstBlock); - if (!remove) - { - dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; - } - dir_backup = dir; + UpdatedDir.Dir[i] = direntry; + *(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock); + UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter+1; break; } } - + *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } int fileBlocks = BE16(direntry.BlockCount); + + BlockAlloc UpdatedBat = *CurrentBat; u16 nextBlock; // keep assuming no freespace fragmentation, and copy over all the data for (int i = 0; i < fileBlocks; ++i) @@ -671,42 +692,24 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks, i if (i == fileBlocks-1) nextBlock = 0xFFFF; else - nextBlock = NextFreeBlock(firstBlock+1); - bat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + nextBlock = UpdatedBat.NextFreeBlock(firstBlock+1); + UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); firstBlock = nextBlock; } - - bat_backup = bat; -/* u16 last = BE16(bat_backup.LastAllocated); - u16 i = (last - 4); - int j = 2; - while(j < BE16(direntry.BlockCount) + 1) + *(u16*)&UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); + *(u16*)&UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat ) { - bat_backup.Map[i] = BE16(last + (u16)j); - i++; - j++; + CurrentBat = &bat; + PreviousBat = &bat_backup; } - bat_backup.Map[i++] = 0xFFFF; - //Set bat.map to 0 for each block that was removed - for (int k = 0; k < remove; k++) + else { - bat_backup.Map[i++] = 0x0000; + CurrentBat = &bat_backup; + PreviousBat = &bat; } - */ - //update last allocated block -/* *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); -*/ - //update freespace counter - *(u16*)&bat_backup.FreeBlocks = BE16(BE16(bat_backup.FreeBlocks) - fileBlocks); - - if (!remove) - { // ... and dir update counter - *(u16*)&dir_backup.UpdateCounter = BE16(BE16(dir_backup.UpdateCounter) + 1); - // ... and bat update counter - *(u16*)&bat_backup.UpdateCounter = BE16(BE16(bat_backup.UpdateCounter) + 1); - } - bat = bat_backup; return SUCCESS; } @@ -716,87 +719,59 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array return NOMEMCARD; if (index >= DIRLEN) return DELETE_FAIL; - - dir_backup = dir; - bat_backup = bat; u16 startingblock = BE16(dir.Dir[index].FirstBlock); u16 numberofblocks = BE16(dir.Dir[index].BlockCount); - if (!ClearBlocks(startingblock, numberofblocks)) + + BlockAlloc UpdatedBat = *CurrentBat; + if (!UpdatedBat.ClearBlocks(startingblock, numberofblocks)) return DELETE_FAIL; + *(u16*)&UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat ) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; + } + + Directory UpdatedDir = *CurrentDir; + *(u32*)&UpdatedDir.Dir[index].Gamecode = 0; + *(u16*)&UpdatedDir.Dir[index].Makercode = 0; + memset(UpdatedDir.Dir[index].Filename, 0, 0x20); + strcpy((char*)UpdatedDir.Dir[index].Filename, "Broken File000"); + *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); + *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } - - memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE); - - *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); - *(u16*)&bat.UpdateCounter = BE16(BE16(bat.UpdateCounter) + 1); - return SUCCESS; - /* - //error checking - u16 startingblock = 0; - for (int i = 0; i < DIRLEN; i++) - { - if (startingblock > BE16(dir.Dir[i].FirstBlock)) - return DELETE_FAIL; - startingblock = BE16(dir.Dir[i].FirstBlock); - } - - //backup the directory and bat (not really needed here but meh :P - dir_backup = dir; - bat_backup = bat; - - //free the blocks - int blocks_left = BE16(dir.Dir[index].BlockCount); - *(u16*)&bat.LastAllocated = BE16(BE16(dir.Dir[index].FirstBlock) - 1); - - u8 nextIndex = index + 1; - memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE); - - while (nextIndex < DIRLEN) - { - DEntry tempDEntry; - GetDEntry(nextIndex, tempDEntry); - std::vector saveData; - u16 size = 0; - //Only get file data if it is a valid dir entry - if (BE16(tempDEntry.FirstBlock) != 0xFFFF) - { - *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry.BlockCount)); - - size = DEntry_BlockCount(nextIndex); - if (size != 0xFFFF) - { - saveData.reserve(size); - switch (GetSaveData(nextIndex, saveData)) - { - case NOMEMCARD: - break; - case FAIL: - return FAIL; - } - } - } - memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE); - //Only call import file if GetSaveData returns SUCCESS - if (saveData.size() == size) - { - ImportFile(tempDEntry, saveData, blocks_left); - } - nextIndex++; - - } - //Added to clean up if removing last file - if (BE16(bat.LastAllocated) == (u16)4) - { - for (int j = 0; j < blocks_left; j++) - { - bat.Map[j] = 0x0000; - } - } - // increment update counter - *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); - */ } u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) @@ -820,7 +795,7 @@ u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) case NOMEMCARD: return NOMEMCARD; default: - return ImportFile(tempDEntry, saveData, 0); + return ImportFile(tempDEntry, saveData); } } @@ -922,7 +897,7 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s ret = WRITEFAIL; } else - ret = ImportFile(tempDEntry, saveData, 0); + ret = ImportFile(tempDEntry, saveData); return ret; } @@ -1053,7 +1028,7 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const if (!m_valid) return false; - int flags = dir.Dir[index].BIFlags; + int flags = CurrentDir->Dir[index].BIFlags; // Timesplitters 2 is the only game that I see this in // May be a hack if (flags == 0xFB) flags = ~flags; @@ -1063,8 +1038,8 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const if (bnrFormat == 0) return false; - u32 DataOffset = BE32(dir.Dir[index].ImageOffset); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) { @@ -1098,17 +1073,17 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon int fmtCheck = 0; - int formats = BE16(dir.Dir[index].IconFmt); - int fdelays = BE16(dir.Dir[index].AnimSpeed); + int formats = BE16(CurrentDir->Dir[index].IconFmt); + int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); - int flags = dir.Dir[index].BIFlags; + int flags = CurrentDir->Dir[index].BIFlags; // Timesplitters 2 is the only game that I see this in // May be a hack if (flags == 0xFB) flags = ~flags; int bnrFormat = (flags&3); - u32 DataOffset = BE32(dir.Dir[index].ImageOffset); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) { diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index e66f77887e..dfa6bd6f65 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -157,6 +157,7 @@ private: u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum } dir, dir_backup; + Directory *CurrentDir, *PreviousDir; struct BlockAlloc { u16 Checksum; //0x0000 2 Additive Checksum u16 Checksum_Inv; //0x0002 2 Inverse Checksum @@ -164,7 +165,12 @@ private: u8 FreeBlocks[2]; //0x0006 2 free Blocks u8 LastAllocated[2];//0x0008 2 last allocated Block u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks + u16 GetNextBlock(u16 Block) const; + u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; + bool ClearBlocks(u16 StartingBlock, u16 Length); } bat,bat_backup; + + BlockAlloc *CurrentBat, *PreviousBat; struct GCMC_Header { Header *hdr; @@ -219,9 +225,6 @@ public: std::string GetSaveComment2(u8 index) const; // Copies a DEntry from u8 index to DEntry& data bool GetDEntry(u8 index, DEntry &dest) const; - u16 GetNextBlock(u16 Block) const; - u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; - bool ClearBlocks(u16 StartingBlock, u16 Length); // assumes there's enough space in buffer // old determines if function uses old or new method of copying data @@ -230,8 +233,7 @@ public: u32 GetSaveData(u8 index, std::vector &saveBlocks) const; // adds the file to the directory and copies its contents - // if remove > 0 it will pad bat.map with 0's sizeof remove - u32 ImportFile(DEntry& direntry, std::vector &saveBlocks, int remove); + u32 ImportFile(DEntry& direntry, std::vector &saveBlocks); // delete a file from the directory u32 RemoveFile(u8 index); diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 84e6eb8b1d..a6ed1513c6 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -730,8 +730,8 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) wxBlock.Printf(wxT("%10d"), blocks); m_MemcardList[card]->SetItem(index,COLUMN_BLOCKS, wxBlock); firstblock = memoryCard[card]->DEntry_FirstBlock(fileIndex); - if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 - wxFirstBlock.Printf(wxT("%15d"), firstblock-4); + //if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 + wxFirstBlock.Printf(wxT("%15d"), firstblock); m_MemcardList[card]->SetItem(index, COLUMN_FIRSTBLOCK, wxFirstBlock); m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); From 0aeb94d3bef7cef475cfb7bf7655b7bc9446448a Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 17:40:06 -0800 Subject: [PATCH 07/10] disable changing a dentry to "broken file" before removing it, the ipl does not always do this Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 9b9d39fc02..38f7a20528 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -740,6 +740,9 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array } Directory UpdatedDir = *CurrentDir; + /* + // TODO: determine when this is used, even on the same memory card I have seen + // both update to broken file, and not updated *(u32*)&UpdatedDir.Dir[index].Gamecode = 0; *(u16*)&UpdatedDir.Dir[index].Makercode = 0; memset(UpdatedDir.Dir[index].Filename, 0, 0x20); @@ -757,6 +760,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array CurrentDir = &dir_backup; PreviousDir = &dir; } + */ memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); *PreviousDir = UpdatedDir; From ebdab914cbd90c28c33cd1f81051f7b100e3f390 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 17:49:17 -0800 Subject: [PATCH 08/10] Change UpdateCounter to u16 Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 14 +++++++------- Source/Core/Core/Src/HW/GCMemcard.h | 7 +++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 38f7a20528..728f9c5b36 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -240,7 +240,6 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) } if (BE16(bat.UpdateCounter) > BE16(bat_backup.UpdateCounter)) { - PanicAlert("jere, %x, %x",BE16(bat.UpdateCounter) , BE16(bat_backup.UpdateCounter)); CurrentBat = &bat; PreviousBat = &bat_backup; } @@ -564,6 +563,7 @@ bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const dest = CurrentDir->Dir[index]; return true; } + u16 GCMemcard::BlockAlloc::GetNextBlock(u16 Block) const { if ((Block < MC_FST_BLOCKS) || (Block > 4091)) @@ -667,7 +667,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) break; } } - *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); *PreviousDir = UpdatedDir; if (PreviousDir == &dir ) { @@ -697,7 +697,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) firstBlock = nextBlock; } *(u16*)&UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); - *(u16*)&UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); *PreviousBat = UpdatedBat; if (PreviousBat == &bat ) { @@ -726,7 +726,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array BlockAlloc UpdatedBat = *CurrentBat; if (!UpdatedBat.ClearBlocks(startingblock, numberofblocks)) return DELETE_FAIL; - *(u16*)&UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); *PreviousBat = UpdatedBat; if (PreviousBat == &bat ) { @@ -762,7 +762,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array } */ memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); - *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); *PreviousDir = UpdatedDir; if (PreviousDir == &dir ) { @@ -1245,13 +1245,13 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) Directory *p_dir = GCP.dir, *p_dir_backup = GCP.dir_backup; *(u16*)&p_dir->UpdateCounter = 0; - *(u16*)&p_dir_backup->UpdateCounter = BE16(1); + p_dir_backup->UpdateCounter = BE16(1); calc_checksumsBE((u16*)p_dir, 0xFFE, &p_dir->Checksum, &p_dir->Checksum_Inv); calc_checksumsBE((u16*)p_dir_backup, 0xFFE, &p_dir_backup->Checksum, &p_dir_backup->Checksum_Inv); BlockAlloc *p_bat = GCP.bat, *p_bat_backup = GCP.bat_backup; - *(u16*)&p_bat_backup->UpdateCounter = BE16(1); + p_bat_backup->UpdateCounter = BE16(1); *(u16*)&p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); *(u16*)&p_bat->LastAllocated = *(u16*)&p_bat_backup->LastAllocated = BE16(4); calc_checksumsBE((u16*)p_bat+2, 0xFFE, &p_bat->Checksum, &p_bat->Checksum_Inv); diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index dfa6bd6f65..b9344bceb3 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -27,7 +27,6 @@ #define BE32(x) (Common::swap32(x)) #define BE16(x) (Common::swap16(x)) #define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8))); - enum { SLOT_A = 0, @@ -98,7 +97,7 @@ private: u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits u16 Encoding; //0x0024 2 encoding (ASCII or japanese) u8 Unused1[468]; //0x0026 468 unused (0xff) - u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused) + u16 UpdateCounter;//0x01fa 2 update Counter (?, probably unused) u16 Checksum; //0x01fc 2 Additive Checksum u16 Checksum_Inv; //0x01fe 2 Inverse Checksum u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff) @@ -152,7 +151,7 @@ private: struct Directory { DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127) u8 Padding[0x3a]; - u8 UpdateCounter[2];//0x1ffa 2 update Counter + u16 UpdateCounter; //0x1ffa 2 update Counter u16 Checksum; //0x1ffc 2 Additive Checksum u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum } dir, dir_backup; @@ -161,7 +160,7 @@ private: struct BlockAlloc { u16 Checksum; //0x0000 2 Additive Checksum u16 Checksum_Inv; //0x0002 2 Inverse Checksum - u8 UpdateCounter[2];//0x0004 2 update Counter + u16 UpdateCounter; //0x0004 2 update Counter u8 FreeBlocks[2]; //0x0006 2 free Blocks u8 LastAllocated[2];//0x0008 2 last allocated Block u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks From e68b892cc63d9324fc932c3337463ead1e651b45 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 17:55:10 -0800 Subject: [PATCH 09/10] more changes from u8[] to u16/u32 Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 17 +++++++---------- Source/Core/Core/Src/HW/GCMemcard.h | 16 ++++++++-------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 728f9c5b36..7423f9ca24 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -595,7 +595,7 @@ bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) } for (int i = 0; i < length; ++i) Map[blocks.at(i)-MC_FST_BLOCKS] = 0; - *(u16*)&FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); + FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); return true; } @@ -646,10 +646,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) return TITLEPRESENT; } - // find first free data block -- assume no freespace fragmentation - //int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - //int firstFree1 = BE16(bat.LastAllocated) + 1; - + // find first free data block u16 firstBlock = CurrentBat->NextFreeBlock(); Directory UpdatedDir = *CurrentDir; @@ -696,7 +693,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); firstBlock = nextBlock; } - *(u16*)&UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); + UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); *PreviousBat = UpdatedBat; if (PreviousBat == &bat ) @@ -1235,8 +1232,8 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand &= (u64)0x0000000000007fffULL; } - *(u32*)&p_hdr->SramBias = g_SRAM.counter_bias; - *(u32*)&p_hdr->SramLang = g_SRAM.lang; + p_hdr->SramBias = g_SRAM.counter_bias; + p_hdr->SramLang = g_SRAM.lang; // TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B *(u32*)&p_hdr->Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; *(u16*)&p_hdr->deviceID = 0; @@ -1252,8 +1249,8 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) BlockAlloc *p_bat = GCP.bat, *p_bat_backup = GCP.bat_backup; p_bat_backup->UpdateCounter = BE16(1); - *(u16*)&p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - *(u16*)&p_bat->LastAllocated = *(u16*)&p_bat_backup->LastAllocated = BE16(4); + p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); + p_bat->LastAllocated = p_bat_backup->LastAllocated = BE16(4); calc_checksumsBE((u16*)p_bat+2, 0xFFE, &p_bat->Checksum, &p_bat->Checksum_Inv); calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv); } diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index b9344bceb3..c04217d895 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -89,15 +89,15 @@ private: // Serial in libogc u8 serial[12]; //0x0000 12 ? u64 formatTime; //0x000c 8 time of format (OSTime value) - u8 SramBias[4]; //0x0014 4 sram bias at time of format - u8 SramLang[4]; //0x0018 4 sram language + u32 SramBias; //0x0014 4 sram bias at time of format + u32 SramLang; //0x0018 4 sram language u8 Unk2[4]; //0x001c 4 ? almost always 0 // end Serial in libogc u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits u16 Encoding; //0x0024 2 encoding (ASCII or japanese) u8 Unused1[468]; //0x0026 468 unused (0xff) - u16 UpdateCounter;//0x01fa 2 update Counter (?, probably unused) + u16 UpdateCounter; //0x01fa 2 update Counter (?, probably unused) u16 Checksum; //0x01fc 2 Additive Checksum u16 Checksum_Inv; //0x01fe 2 Inverse Checksum u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff) @@ -158,11 +158,11 @@ private: Directory *CurrentDir, *PreviousDir; struct BlockAlloc { - u16 Checksum; //0x0000 2 Additive Checksum - u16 Checksum_Inv; //0x0002 2 Inverse Checksum - u16 UpdateCounter; //0x0004 2 update Counter - u8 FreeBlocks[2]; //0x0006 2 free Blocks - u8 LastAllocated[2];//0x0008 2 last allocated Block + u16 Checksum; //0x0000 2 Additive Checksum + u16 Checksum_Inv; //0x0002 2 Inverse Checksum + u16 UpdateCounter; //0x0004 2 update Counter + u16 FreeBlocks; //0x0006 2 free Blocks + u16 LastAllocated; //0x0008 2 last allocated Block u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks u16 GetNextBlock(u16 Block) const; u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; From 643770bff9a69b9fbfc4da08c6e00482bfd1a816 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 6 Feb 2012 23:48:13 -0800 Subject: [PATCH 10/10] more work towards correct file importing Signed-off-by: LPFaint99 --- Source/Core/Core/Src/HW/GCMemcard.cpp | 22 +++++++++++++++++----- Source/Core/Core/Src/HW/GCMemcard.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 7423f9ca24..5ba0c2aaa6 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -573,9 +573,16 @@ u16 GCMemcard::BlockAlloc::GetNextBlock(u16 Block) const u16 GCMemcard::BlockAlloc::NextFreeBlock(u16 StartingBlock) const { - for (u16 i = StartingBlock; i < BAT_SIZE; ++i) - if (Map[i-MC_FST_BLOCKS] == 0) - return i; + if (FreeBlocks) + { + for (u16 i = StartingBlock; i < BAT_SIZE; ++i) + if (Map[i-MC_FST_BLOCKS] == 0) + return i; + for (u16 i = 0; i < StartingBlock; ++i) + if (Map[i-MC_FST_BLOCKS] == 0) + return i; + } + return 0xFFFF; } bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) @@ -647,8 +654,9 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) } // find first free data block - u16 firstBlock = CurrentBat->NextFreeBlock(); - + u16 firstBlock = CurrentBat->NextFreeBlock(BE16(CurrentBat->LastAllocated)); + if (firstBlock == 0xFFFF) + return OUTOFBLOCKS; Directory UpdatedDir = *CurrentDir; // find first free dir entry @@ -685,14 +693,18 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) // keep assuming no freespace fragmentation, and copy over all the data for (int i = 0; i < fileBlocks; ++i) { + if (firstBlock == 0xFFFF) + PanicAlert("Fatal Error"); mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; if (i == fileBlocks-1) nextBlock = 0xFFFF; else nextBlock = UpdatedBat.NextFreeBlock(firstBlock+1); UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + UpdatedBat.LastAllocated = BE16(firstBlock); firstBlock = nextBlock; } + UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); *PreviousBat = UpdatedBat; diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index c04217d895..be78bb527c 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -24,6 +24,7 @@ #include "StringUtil.h" #include "EXI_DeviceIPL.h" +#define BE64(x) (Common::swap64(x)) #define BE32(x) (Common::swap32(x)) #define BE16(x) (Common::swap16(x)) #define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));