diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp index 15173e0e48..d603e1075e 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp @@ -304,7 +304,7 @@ void GCMemcard::UpdateBat(const BlockAlloc& bat) bool GCMemcard::IsShiftJIS() const { - return m_header_block.m_data.m_encoding != 0; + return m_header_block.IsShiftJIS(); } bool GCMemcard::Save() @@ -1274,15 +1274,6 @@ DEntry::DEntry() memset(reinterpret_cast(this), 0xFF, DENTRY_SIZE); } -std::string DEntry::GCI_FileName() const -{ - std::string filename = - std::string(reinterpret_cast(m_makercode.data()), m_makercode.size()) + '-' + - std::string(reinterpret_cast(m_gamecode.data()), m_gamecode.size()) + '-' + - reinterpret_cast(m_filename.data()) + ".gci"; - return Common::EscapeFileName(filename); -} - void Header::FixChecksums() { std::tie(m_checksum, m_checksum_inv) = CalculateChecksums(); @@ -1324,6 +1315,11 @@ GCMemcardErrorCode Header::CheckForErrors(u16 card_size_mbits) const return error_code; } +bool Header::IsShiftJIS() const +{ + return m_data.m_encoding != 0; +} + Directory::Directory() { memset(reinterpret_cast(this), 0xFF, BLOCK_SIZE); diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.h b/Source/Core/Core/HW/GCMemcard/GCMemcard.h index ed4c36ba20..80a2b3eea4 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.h @@ -231,6 +231,8 @@ struct Header std::pair CalculateChecksums() const; GCMemcardErrorCode CheckForErrors(u16 card_size_mbits) const; + + bool IsShiftJIS() const; }; static_assert(sizeof(Header) == BLOCK_SIZE); static_assert(std::is_trivially_copyable_v
); @@ -239,9 +241,6 @@ struct DEntry { DEntry(); - // TODO: This probably shouldn't be here at all? - std::string GCI_FileName() const; - static constexpr std::array UNINITIALIZED_GAMECODE{{0xFF, 0xFF, 0xFF, 0xFF}}; // 4 bytes at 0x00: Gamecode diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp index 3f02ef16b1..f7b318a6eb 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,28 @@ static const char* MC_HDR = "MC_SYSTEM_AREA"; +static std::string GenerateDefaultGCIFilename(const Memcard::DEntry& entry, + bool card_encoding_is_shift_jis) +{ + const auto string_decoder = card_encoding_is_shift_jis ? SHIFTJISToUTF8 : CP1252ToUTF8; + const auto strip_null = [](const std::string_view& s) { + auto offset = s.find('\0'); + if (offset == std::string_view::npos) + return s; + return s.substr(0, offset); + }; + + const std::string_view makercode(reinterpret_cast(entry.m_makercode.data()), + entry.m_makercode.size()); + const std::string_view gamecode(reinterpret_cast(entry.m_gamecode.data()), + entry.m_gamecode.size()); + const std::string_view filename(reinterpret_cast(entry.m_filename.data()), + entry.m_filename.size()); + return Common::EscapeFileName(fmt::format("{}-{}-{}.gci", strip_null(string_decoder(makercode)), + strip_null(string_decoder(gamecode)), + strip_null(string_decoder(filename)))); +} + bool GCMemcardDirectory::LoadGCI(Memcard::GCIFile gci) { // check if any already loaded file has the same internal name as the new file @@ -102,7 +125,8 @@ bool GCMemcardDirectory::LoadGCI(Memcard::GCIFile gci) // This is only used by NetPlay but it made sense to put it here to keep the relevant code together std::vector GCMemcardDirectory::GetFileNamesForGameID(const std::string& directory, - const std::string& game_id) + const std::string& game_id, + bool card_encoding_is_shift_jis) { std::vector filenames; @@ -123,7 +147,8 @@ std::vector GCMemcardDirectory::GetFileNamesForGameID(const std::st if (!gci_file.ReadBytes(&gci.m_gci_header, Memcard::DENTRY_SIZE)) continue; - const std::string gci_filename = gci.m_gci_header.GCI_FileName(); + const std::string gci_filename = + GenerateDefaultGCIFilename(gci.m_gci_header, card_encoding_is_shift_jis); if (std::find(loaded_saves.begin(), loaded_saves.end(), gci_filename) != loaded_saves.end()) continue; @@ -614,7 +639,8 @@ void GCMemcardDirectory::FlushToFile() } if (save.m_filename.empty()) { - std::string default_save_name = m_save_directory + save.m_gci_header.GCI_FileName(); + std::string default_save_name = + m_save_directory + GenerateDefaultGCIFilename(save.m_gci_header, m_hdr.IsShiftJIS()); // Check to see if another file is using the same name // This seems unlikely except in the case of file corruption diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h index 5b02700a61..b61ad360b6 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h @@ -32,7 +32,8 @@ public: GCMemcardDirectory& operator=(GCMemcardDirectory&&) = delete; static std::vector GetFileNamesForGameID(const std::string& directory, - const std::string& game_id); + const std::string& game_id, + bool card_encoding_is_shift_jis); void FlushToFile(); void FlushThread(); s32 Read(u32 src_address, s32 length, u8* dest_address) override; diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 18076ada29..9c0ba0a53d 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -1686,7 +1686,8 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info) return true; const auto game_region = sync_info.game->GetRegion(); - const std::string region = Config::GetDirectoryForRegion(Config::ToGameCubeRegion(game_region)); + const auto gamecube_region = Config::ToGameCubeRegion(game_region); + const std::string region = Config::GetDirectoryForRegion(gamecube_region); for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) { @@ -1733,8 +1734,8 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info) if (File::IsDirectory(path)) { - std::vector files = - GCMemcardDirectory::GetFileNamesForGameID(path + DIR_SEP, sync_info.game->GetGameID()); + std::vector files = GCMemcardDirectory::GetFileNamesForGameID( + path + DIR_SEP, sync_info.game->GetGameID(), gamecube_region == DiscIO::Region::NTSC_J); pac << static_cast(files.size());