From 58f21830bd6ebec3874a1c811a0a329e24ffb84d Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 19 Oct 2019 16:06:02 +0200 Subject: [PATCH] GCMemcard: Read file comments according to logical data offsets instead of physical data offsets. --- Source/Core/Core/HW/GCMemcard/GCMemcard.cpp | 52 +++++++++------------ Source/Core/Core/HW/GCMemcard/GCMemcard.h | 9 ++-- Source/Core/DolphinQt/GCMemcardManager.cpp | 22 ++++----- 3 files changed, 35 insertions(+), 48 deletions(-) diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp index 33c6c58858..07dcb01b69 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp @@ -639,43 +639,33 @@ std::optional> GCMemcard::GetSaveDataBytes(u8 save_index, size_t return std::make_optional(std::move(result)); } -u32 GCMemcard::DEntry_CommentsAddress(u8 index) const +std::optional> GCMemcard::GetSaveComments(u8 index) const { if (!m_valid || index >= DIRLEN) - return 0xFFFF; + return std::nullopt; - return GetActiveDirectory().m_dir_entries[index].m_comments_address; -} + const u32 address = GetActiveDirectory().m_dir_entries[index].m_comments_address; + if (address == 0xFFFFFFFF) + return std::nullopt; -std::string GCMemcard::GetSaveComment1(u8 index) const -{ - if (!m_valid || index >= DIRLEN) - return ""; + const auto data = GetSaveDataBytes(index, address, DENTRY_STRLEN * 2); + if (!data || data->size() != DENTRY_STRLEN * 2) + return std::nullopt; - u32 Comment1 = GetActiveDirectory().m_dir_entries[index].m_comments_address; - u32 DataBlock = GetActiveDirectory().m_dir_entries[index].m_first_block - MC_FST_BLOCKS; - if ((DataBlock > m_size_blocks) || (Comment1 == 0xFFFFFFFF)) - { - return ""; - } - return std::string((const char*)m_data_blocks[DataBlock].m_block.data() + Comment1, - DENTRY_STRLEN); -} + const auto string_decoder = IsShiftJIS() ? SHIFTJISToUTF8 : CP1252ToUTF8; + const auto strip_null = [](const std::string& s) { + auto offset = s.find('\0'); + if (offset == std::string::npos) + offset = s.length(); + return s.substr(0, offset); + }; -std::string GCMemcard::GetSaveComment2(u8 index) const -{ - if (!m_valid || index >= DIRLEN) - return ""; - - u32 Comment1 = GetActiveDirectory().m_dir_entries[index].m_comments_address; - u32 Comment2 = Comment1 + DENTRY_STRLEN; - u32 DataBlock = GetActiveDirectory().m_dir_entries[index].m_first_block - MC_FST_BLOCKS; - if ((DataBlock > m_size_blocks) || (Comment1 == 0xFFFFFFFF)) - { - return ""; - } - return std::string((const char*)m_data_blocks[DataBlock].m_block.data() + Comment2, - DENTRY_STRLEN); + const u8* address_1 = data->data(); + const u8* address_2 = address_1 + DENTRY_STRLEN; + const std::string encoded_1(reinterpret_cast(address_1), DENTRY_STRLEN); + const std::string encoded_2(reinterpret_cast(address_2), DENTRY_STRLEN); + return std::make_pair(strip_null(string_decoder(encoded_1)), + strip_null(string_decoder(encoded_2))); } std::optional GCMemcard::GetDEntry(u8 index) const diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.h b/Source/Core/Core/HW/GCMemcard/GCMemcard.h index d8c7b79486..24db3194ea 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.h @@ -118,7 +118,7 @@ constexpr u32 MC_FST_BLOCKS = 0x05; // maximum number of saves that can be stored on a single memory card constexpr u8 DIRLEN = 0x7F; -// maximum size of memory card file comment in bytes +// maximum size of a single memory card file comment in bytes constexpr u32 DENTRY_STRLEN = 0x20; // size of a single entry in the Directory in bytes @@ -456,9 +456,10 @@ public: GetSaveDataBytes(u8 save_index, size_t offset = 0, size_t length = std::numeric_limits::max()) const; - u32 DEntry_CommentsAddress(u8 index) const; - std::string GetSaveComment1(u8 index) const; - std::string GetSaveComment2(u8 index) const; + // Returns, if available, the two strings shown on the save file in the GC BIOS, in UTF8. + // The first is the big line on top, usually the game title, and the second is the smaller line + // next to the block size, often a progress indicator or subtitle. + std::optional> GetSaveComments(u8 index) const; // Fetches a DEntry from the given file index. std::optional GetDEntry(u8 index) const; diff --git a/Source/Core/DolphinQt/GCMemcardManager.cpp b/Source/Core/DolphinQt/GCMemcardManager.cpp index 84dc10d02b..17d5d162e3 100644 --- a/Source/Core/DolphinQt/GCMemcardManager.cpp +++ b/Source/Core/DolphinQt/GCMemcardManager.cpp @@ -186,14 +186,6 @@ void GCMemcardManager::UpdateSlotTable(int slot) return item; }; - const auto strip_garbage = [](const std::string& s) { - auto offset = s.find('\0'); - if (offset == std::string::npos) - offset = s.length(); - - return s.substr(0, offset); - }; - const u8 num_files = memcard->GetNumFiles(); m_slot_active_icons[slot].reserve(num_files); for (int i = 0; i < num_files; i++) @@ -201,12 +193,16 @@ void GCMemcardManager::UpdateSlotTable(int slot) int file_index = memcard->GetFileIndex(i); table->setRowCount(i + 1); - auto const string_decoder = memcard->IsShiftJIS() ? SHIFTJISToUTF8 : CP1252ToUTF8; + const auto file_comments = memcard->GetSaveComments(file_index); + + QString title; + QString comment; + if (file_comments) + { + title = QString::fromStdString(file_comments->first); + comment = QString::fromStdString(file_comments->second); + } - QString title = - QString::fromStdString(strip_garbage(string_decoder(memcard->GetSaveComment1(file_index)))); - QString comment = - QString::fromStdString(strip_garbage(string_decoder(memcard->GetSaveComment2(file_index)))); QString blocks = QStringLiteral("%1").arg(memcard->DEntry_BlockCount(file_index)); QString block_count = QStringLiteral("%1").arg(memcard->DEntry_FirstBlock(file_index));