mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-24 06:14:54 +00:00
GCMemcardDirectory: Decode and strip strings for GCI filenames.
This commit is contained in:
parent
c517e92719
commit
4b0312ecf8
5 changed files with 43 additions and 20 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue