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
{
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<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()
{
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<u8*>(this), 0xFF, BLOCK_SIZE);

View File

@ -231,6 +231,8 @@ struct Header
std::pair<u16, u16> 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<Header>);
@ -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<u8, 4> UNINITIALIZED_GAMECODE{{0xFF, 0xFF, 0xFF, 0xFF}};
// 4 bytes at 0x00: Gamecode

View File

@ -9,6 +9,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <vector>
#include <fmt/format.h>
@ -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<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)
{
// 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<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;
@ -123,7 +147,8 @@ std::vector<std::string> 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

View File

@ -32,7 +32,8 @@ public:
GCMemcardDirectory& operator=(GCMemcardDirectory&&) = delete;
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 FlushThread();
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;
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<std::string> files =
GCMemcardDirectory::GetFileNamesForGameID(path + DIR_SEP, sync_info.game->GetGameID());
std::vector<std::string> files = GCMemcardDirectory::GetFileNamesForGameID(
path + DIR_SEP, sync_info.game->GetGameID(), gamecube_region == DiscIO::Region::NTSC_J);
pac << static_cast<u8>(files.size());