GCMemcardDirectory: Decode and strip strings for GCI filenames.

This commit is contained in:
Admiral H. Curtiss 2022-10-30 02:40:54 +01:00
parent c517e92719
commit 4b0312ecf8
No known key found for this signature in database
GPG key ID: F051B4C4044F33FB
5 changed files with 43 additions and 20 deletions

View file

@ -304,7 +304,7 @@ void GCMemcard::UpdateBat(const BlockAlloc& bat)
bool GCMemcard::IsShiftJIS() const bool GCMemcard::IsShiftJIS() const
{ {
return m_header_block.m_data.m_encoding != 0; return m_header_block.IsShiftJIS();
} }
bool GCMemcard::Save() bool GCMemcard::Save()
@ -1274,15 +1274,6 @@ DEntry::DEntry()
memset(reinterpret_cast<u8*>(this), 0xFF, DENTRY_SIZE); memset(reinterpret_cast<u8*>(this), 0xFF, DENTRY_SIZE);
} }
std::string DEntry::GCI_FileName() const
{
std::string filename =
std::string(reinterpret_cast<const char*>(m_makercode.data()), m_makercode.size()) + '-' +
std::string(reinterpret_cast<const char*>(m_gamecode.data()), m_gamecode.size()) + '-' +
reinterpret_cast<const char*>(m_filename.data()) + ".gci";
return Common::EscapeFileName(filename);
}
void Header::FixChecksums() void Header::FixChecksums()
{ {
std::tie(m_checksum, m_checksum_inv) = CalculateChecksums(); std::tie(m_checksum, m_checksum_inv) = CalculateChecksums();
@ -1324,6 +1315,11 @@ GCMemcardErrorCode Header::CheckForErrors(u16 card_size_mbits) const
return error_code; return error_code;
} }
bool Header::IsShiftJIS() const
{
return m_data.m_encoding != 0;
}
Directory::Directory() Directory::Directory()
{ {
memset(reinterpret_cast<u8*>(this), 0xFF, BLOCK_SIZE); memset(reinterpret_cast<u8*>(this), 0xFF, BLOCK_SIZE);

View file

@ -231,6 +231,8 @@ struct Header
std::pair<u16, u16> CalculateChecksums() const; std::pair<u16, u16> CalculateChecksums() const;
GCMemcardErrorCode CheckForErrors(u16 card_size_mbits) const; GCMemcardErrorCode CheckForErrors(u16 card_size_mbits) const;
bool IsShiftJIS() const;
}; };
static_assert(sizeof(Header) == BLOCK_SIZE); static_assert(sizeof(Header) == BLOCK_SIZE);
static_assert(std::is_trivially_copyable_v<Header>); static_assert(std::is_trivially_copyable_v<Header>);
@ -239,9 +241,6 @@ struct DEntry
{ {
DEntry(); DEntry();
// TODO: This probably shouldn't be here at all?
std::string GCI_FileName() const;
static constexpr std::array<u8, 4> UNINITIALIZED_GAMECODE{{0xFF, 0xFF, 0xFF, 0xFF}}; static constexpr std::array<u8, 4> UNINITIALIZED_GAMECODE{{0xFF, 0xFF, 0xFF, 0xFF}};
// 4 bytes at 0x00: Gamecode // 4 bytes at 0x00: Gamecode

View file

@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
#include <fmt/format.h> #include <fmt/format.h>
@ -39,6 +40,28 @@
static const char* MC_HDR = "MC_SYSTEM_AREA"; 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<const char*>(entry.m_makercode.data()),
entry.m_makercode.size());
const std::string_view gamecode(reinterpret_cast<const char*>(entry.m_gamecode.data()),
entry.m_gamecode.size());
const std::string_view filename(reinterpret_cast<const char*>(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) bool GCMemcardDirectory::LoadGCI(Memcard::GCIFile gci)
{ {
// check if any already loaded file has the same internal name as the new file // 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 // This is only used by NetPlay but it made sense to put it here to keep the relevant code together
std::vector<std::string> GCMemcardDirectory::GetFileNamesForGameID(const std::string& directory, std::vector<std::string> GCMemcardDirectory::GetFileNamesForGameID(const std::string& directory,
const std::string& game_id) const std::string& game_id,
bool card_encoding_is_shift_jis)
{ {
std::vector<std::string> filenames; std::vector<std::string> filenames;
@ -123,7 +147,8 @@ std::vector<std::string> GCMemcardDirectory::GetFileNamesForGameID(const std::st
if (!gci_file.ReadBytes(&gci.m_gci_header, Memcard::DENTRY_SIZE)) if (!gci_file.ReadBytes(&gci.m_gci_header, Memcard::DENTRY_SIZE))
continue; 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()) if (std::find(loaded_saves.begin(), loaded_saves.end(), gci_filename) != loaded_saves.end())
continue; continue;
@ -614,7 +639,8 @@ void GCMemcardDirectory::FlushToFile()
} }
if (save.m_filename.empty()) 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 // Check to see if another file is using the same name
// This seems unlikely except in the case of file corruption // This seems unlikely except in the case of file corruption

View file

@ -32,7 +32,8 @@ public:
GCMemcardDirectory& operator=(GCMemcardDirectory&&) = delete; GCMemcardDirectory& operator=(GCMemcardDirectory&&) = delete;
static std::vector<std::string> GetFileNamesForGameID(const std::string& directory, static std::vector<std::string> GetFileNamesForGameID(const std::string& directory,
const std::string& game_id); const std::string& game_id,
bool card_encoding_is_shift_jis);
void FlushToFile(); void FlushToFile();
void FlushThread(); void FlushThread();
s32 Read(u32 src_address, s32 length, u8* dest_address) override; s32 Read(u32 src_address, s32 length, u8* dest_address) override;

View file

@ -1686,7 +1686,8 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info)
return true; return true;
const auto game_region = sync_info.game->GetRegion(); 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) for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
{ {
@ -1733,8 +1734,8 @@ bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info)
if (File::IsDirectory(path)) if (File::IsDirectory(path))
{ {
std::vector<std::string> files = std::vector<std::string> files = GCMemcardDirectory::GetFileNamesForGameID(
GCMemcardDirectory::GetFileNamesForGameID(path + DIR_SEP, sync_info.game->GetGameID()); path + DIR_SEP, sync_info.game->GetGameID(), gamecube_region == DiscIO::Region::NTSC_J);
pac << static_cast<u8>(files.size()); pac << static_cast<u8>(files.size());