MemoryCardImage: Report errors to caller
This commit is contained in:
parent
9dd686a994
commit
1ee5f737ed
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "memory_card_image.h"
|
||||
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "common/bitutils.h"
|
||||
#include "common/byte_stream.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
|
@ -87,12 +88,13 @@ const T* GetFramePtr(const DataArray& data, u32 block, u32 frame)
|
|||
}
|
||||
|
||||
static std::optional<u32> GetNextFreeBlock(const DataArray& data);
|
||||
static bool ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data);
|
||||
static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data);
|
||||
static bool ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data);
|
||||
static bool ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data);
|
||||
static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd);
|
||||
static bool ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd);
|
||||
static bool ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error);
|
||||
static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error);
|
||||
static bool ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error);
|
||||
static bool ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error);
|
||||
static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd,
|
||||
Error* error);
|
||||
static bool ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd, Error* error);
|
||||
} // namespace MemoryCardImage
|
||||
|
||||
bool MemoryCardImage::LoadFromFile(DataArray* data, const char* filename)
|
||||
|
@ -310,7 +312,7 @@ std::vector<MemoryCardImage::FileInfo> MemoryCardImage::EnumerateFiles(const Dat
|
|||
return files;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer)
|
||||
bool MemoryCardImage::ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer, Error* error)
|
||||
{
|
||||
buffer->resize(fi.num_blocks * BLOCK_SIZE);
|
||||
|
||||
|
@ -327,18 +329,21 @@ bool MemoryCardImage::ReadFile(const DataArray& data, const FileInfo& fi, std::v
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer)
|
||||
bool MemoryCardImage::WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer,
|
||||
Error* error)
|
||||
{
|
||||
if (buffer.empty())
|
||||
{
|
||||
Log_ErrorPrint("Failed to write file to memory card: buffer is empty");
|
||||
Error::SetStringView(error, "Buffer is empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 free_block_count = GetFreeBlockCount(*data);
|
||||
const u32 num_blocks = (static_cast<u32>(buffer.size()) + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
|
||||
if (GetFreeBlockCount(*data) < num_blocks)
|
||||
if (free_block_count < num_blocks)
|
||||
{
|
||||
Log_ErrorPrint("Failed to write file to memory card: insufficient free blocks");
|
||||
Error::SetStringFmt(error, "Insufficient free blocks, {} blocks are needed, but only have {}.", num_blocks,
|
||||
free_block_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -482,11 +487,12 @@ bool MemoryCardImage::UndeleteFile(DataArray* data, const FileInfo& fi)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data)
|
||||
bool MemoryCardImage::ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error)
|
||||
{
|
||||
if (file_data.size() != DATA_SIZE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': file is incorrect size.", filename);
|
||||
Error::SetStringFmt(error, "File is incorrect size, expected {} bytes, got {} bytes.", static_cast<u32>(DATA_SIZE),
|
||||
file_data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -494,7 +500,7 @@ bool MemoryCardImage::ImportCardMCD(DataArray* data, const char* filename, std::
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data)
|
||||
bool MemoryCardImage::ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error)
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct GMEHeader
|
||||
|
@ -510,9 +516,12 @@ bool MemoryCardImage::ImportCardGME(DataArray* data, const char* filename, std::
|
|||
static_assert(sizeof(GMEHeader) == 0xF40);
|
||||
#pragma pack(pop)
|
||||
|
||||
if (file_data.size() < (sizeof(GMEHeader) + BLOCK_SIZE))
|
||||
constexpr u32 MIN_SIZE = sizeof(GMEHeader) + BLOCK_SIZE;
|
||||
|
||||
if (file_data.size() < MIN_SIZE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to import GME memory card from '{}': file is incorrect size.", filename);
|
||||
Error::SetStringFmt(error, "File is incorrect size, expected at least {} bytes, got {} bytes.", MIN_SIZE,
|
||||
file_data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -530,20 +539,22 @@ bool MemoryCardImage::ImportCardGME(DataArray* data, const char* filename, std::
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data)
|
||||
bool MemoryCardImage::ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error)
|
||||
{
|
||||
constexpr u32 HEADER_SIZE = 64;
|
||||
constexpr u32 EXPECTED_SIZE = HEADER_SIZE + DATA_SIZE;
|
||||
|
||||
if (file_data.size() != (HEADER_SIZE + DATA_SIZE))
|
||||
if (file_data.size() != EXPECTED_SIZE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': file is incorrect size.", filename);
|
||||
Error::SetStringFmt(error, "File is incorrect size, expected {} bytes, got {} bytes.", EXPECTED_SIZE,
|
||||
file_data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connectix Virtual Game Station format (.MEM): "VgsM", 64 bytes
|
||||
if (file_data[0] != 'V' || file_data[1] != 'g' || file_data[2] != 's' || file_data[3] != 'M')
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': incorrect header.", filename);
|
||||
Error::SetStringView(error, "Incorrect header.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -551,20 +562,22 @@ bool MemoryCardImage::ImportCardVGS(DataArray* data, const char* filename, std::
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data)
|
||||
bool MemoryCardImage::ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error)
|
||||
{
|
||||
constexpr u32 HEADER_SIZE = 256;
|
||||
constexpr u32 EXPECTED_SIZE = HEADER_SIZE + DATA_SIZE;
|
||||
|
||||
if (file_data.size() != (HEADER_SIZE + DATA_SIZE))
|
||||
if (file_data.size() != EXPECTED_SIZE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': file is incorrect size.", filename);
|
||||
Error::SetStringFmt(error, "File is incorrect size, expected {} bytes, got {} bytes.", EXPECTED_SIZE,
|
||||
file_data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connectix Virtual Game Station format (.MEM): "VgsM", 64 bytes
|
||||
if (file_data[0] != 'P' || file_data[1] != 'S' || file_data[2] != 'V')
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': incorrect header.", filename);
|
||||
Error::SetStringView(error, "Incorrect header.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -572,76 +585,72 @@ bool MemoryCardImage::ImportCardPSX(DataArray* data, const char* filename, std::
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data)
|
||||
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error)
|
||||
{
|
||||
const char* extension = std::strrchr(filename, '.');
|
||||
if (!extension)
|
||||
const std::string_view extension = Path::GetExtension(filename);
|
||||
if (extension.empty())
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': missing extension?", filename);
|
||||
Error::SetStringFmt(error, "File must have an extension.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil::Strcasecmp(extension, ".mcd") == 0 || StringUtil::Strcasecmp(extension, ".mcr") == 0 ||
|
||||
StringUtil::Strcasecmp(extension, ".mc") == 0 || StringUtil::Strcasecmp(extension, ".srm") == 0 ||
|
||||
StringUtil::Strcasecmp(extension, ".psm") == 0 || StringUtil::Strcasecmp(extension, ".ps") == 0 ||
|
||||
StringUtil::Strcasecmp(extension, ".ddf") == 0)
|
||||
if (StringUtil::EqualNoCase(extension, "mcd") || StringUtil::EqualNoCase(extension, "mcr") ||
|
||||
StringUtil::EqualNoCase(extension, "mc") || StringUtil::EqualNoCase(extension, "srm") ||
|
||||
StringUtil::EqualNoCase(extension, "psm") || StringUtil::EqualNoCase(extension, "ps") ||
|
||||
StringUtil::EqualNoCase(extension, "ddf"))
|
||||
{
|
||||
return ImportCardMCD(data, filename, std::move(file_data));
|
||||
return ImportCardMCD(data, filename, std::move(file_data), error);
|
||||
}
|
||||
else if (StringUtil::Strcasecmp(extension, ".gme") == 0)
|
||||
else if (StringUtil::EqualNoCase(extension, "gme"))
|
||||
{
|
||||
return ImportCardGME(data, filename, std::move(file_data));
|
||||
return ImportCardGME(data, filename, std::move(file_data), error);
|
||||
}
|
||||
else if (StringUtil::Strcasecmp(extension, ".mem") == 0 || StringUtil::Strcasecmp(extension, ".vgs") == 0)
|
||||
else if (StringUtil::EqualNoCase(extension, "mem") || StringUtil::EqualNoCase(extension, "vgs"))
|
||||
{
|
||||
return ImportCardVGS(data, filename, std::move(file_data));
|
||||
return ImportCardVGS(data, filename, std::move(file_data), error);
|
||||
}
|
||||
else if (StringUtil::Strcasecmp(extension, ".psx") == 0)
|
||||
else if (StringUtil::EqualNoCase(extension, "psx"))
|
||||
{
|
||||
return ImportCardPSX(data, filename, std::move(file_data));
|
||||
return ImportCardPSX(data, filename, std::move(file_data), error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorFmt("Failed to import memory card from '{}': unknown extension?", filename);
|
||||
Error::SetStringFmt(error, "Unknown extension '{}'.", extension);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename)
|
||||
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename, Error* error)
|
||||
{
|
||||
std::optional<std::vector<u8>> file_data = FileSystem::ReadBinaryFile(filename);
|
||||
std::optional<std::vector<u8>> file_data = FileSystem::ReadBinaryFile(filename, error);
|
||||
if (!file_data.has_value())
|
||||
return false;
|
||||
|
||||
return ImportCard(data, filename, std::move(file_data.value()));
|
||||
return ImportCard(data, filename, std::move(file_data.value()), error);
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char* filename)
|
||||
bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<ByteStream> stream =
|
||||
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE |
|
||||
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED);
|
||||
ByteStream::OpenFile(filename,
|
||||
BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE |
|
||||
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED,
|
||||
error);
|
||||
if (!stream)
|
||||
{
|
||||
Log_ErrorFmt("Failed to open '{}' for writing.", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
DirectoryFrame* df_ptr = GetFramePtr<DirectoryFrame>(data, 0, fi.first_block);
|
||||
std::vector<u8> header = std::vector<u8>(static_cast<size_t>(FRAME_SIZE));
|
||||
std::memcpy(header.data(), df_ptr, sizeof(*df_ptr));
|
||||
|
||||
std::vector<u8> blocks;
|
||||
if (!ReadFile(*data, fi, &blocks))
|
||||
{
|
||||
Log_ErrorPrint("Failed to read save blocks from memory card data");
|
||||
if (!ReadFile(*data, fi, &blocks, error))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream->Write(header.data(), static_cast<u32>(header.size())) ||
|
||||
!stream->Write(blocks.data(), static_cast<u32>(blocks.size())) || !stream->Commit())
|
||||
{
|
||||
Log_ErrorFmt("Failed to write exported save to '{}'", filename);
|
||||
Error::SetStringView(error, "Failed to write exported save.");
|
||||
stream->Discard();
|
||||
return false;
|
||||
}
|
||||
|
@ -650,47 +659,45 @@ bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char
|
|||
}
|
||||
|
||||
bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char* filename,
|
||||
const FILESYSTEM_STAT_DATA& sd)
|
||||
const FILESYSTEM_STAT_DATA& sd, Error* error)
|
||||
{
|
||||
// Make sure the size of the actual file is valid
|
||||
if (sd.Size <= FRAME_SIZE || (sd.Size - FRAME_SIZE) % BLOCK_SIZE != 0u || (sd.Size - FRAME_SIZE) / BLOCK_SIZE > 15u)
|
||||
{
|
||||
Log_ErrorFmt("Invalid size for save file '{}'", filename);
|
||||
Error::SetStringView(error, "Invalid size for save file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<ByteStream> stream = ByteStream::OpenFile(filename, BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED);
|
||||
std::unique_ptr<ByteStream> stream =
|
||||
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED, error);
|
||||
if (!stream)
|
||||
{
|
||||
Log_ErrorFmt("Failed to open '{}' for reading", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
DirectoryFrame df;
|
||||
if (stream->Read(&df, FRAME_SIZE) != FRAME_SIZE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to read directory frame from '{}'", filename);
|
||||
Error::SetStringView(error, "Failed to read directory frame.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the size reported by the directory frame is valid
|
||||
if (df.file_size < BLOCK_SIZE || df.file_size % BLOCK_SIZE != 0 || df.file_size / BLOCK_SIZE > 15u)
|
||||
{
|
||||
Log_ErrorFmt("Invalid size ({} bytes) reported by directory frame", df.file_size);
|
||||
Error::SetStringFmt(error, "Invalid size ({} bytes) reported by directory frame.", df.file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> blocks = std::vector<u8>(static_cast<size_t>(df.file_size));
|
||||
if (stream->Read(blocks.data(), df.file_size) != df.file_size)
|
||||
{
|
||||
Log_ErrorFmt("Failed to read block bytes from '{}'", filename);
|
||||
Error::SetStringView(error, "Failed to read block bytes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 num_blocks = (static_cast<u32>(blocks.size()) + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
|
||||
if (GetFreeBlockCount(*data) < num_blocks)
|
||||
{
|
||||
Log_ErrorPrint("Failed to write file to memory card: insufficient free blocks");
|
||||
Error::SetStringView(error, "Insufficient free blocks.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -702,7 +709,7 @@ bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char*
|
|||
{
|
||||
if (!fi.deleted)
|
||||
{
|
||||
Log_ErrorFmt("Save file with the same name '{}' already exists in memory card", fi.filename.c_str());
|
||||
Error::SetStringFmt(error, "Save file with the same name '{}' already exists in memory card", fi.filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -710,33 +717,32 @@ bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char*
|
|||
}
|
||||
}
|
||||
|
||||
return WriteFile(data, df.filename, blocks);
|
||||
return WriteFile(data, df.filename, blocks, error);
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd)
|
||||
bool MemoryCardImage::ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd, Error* error)
|
||||
{
|
||||
const std::string display_name(FileSystem::GetDisplayNameFromPath(filename));
|
||||
const std::string display_name = FileSystem::GetDisplayNameFromPath(filename);
|
||||
std::string save_name(Path::GetFileTitle(filename));
|
||||
if (save_name.length() == 0)
|
||||
{
|
||||
Log_ErrorFmt("Invalid filename: '{}'", filename);
|
||||
Error::SetStringView(error, "Invalid filename.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (save_name.length() > DirectoryFrame::FILE_NAME_LENGTH)
|
||||
save_name.erase(DirectoryFrame::FILE_NAME_LENGTH);
|
||||
|
||||
std::optional<std::vector<u8>> blocks = FileSystem::ReadBinaryFile(filename);
|
||||
std::optional<std::vector<u8>> blocks = FileSystem::ReadBinaryFile(filename, error);
|
||||
if (!blocks.has_value())
|
||||
{
|
||||
Log_ErrorFmt("Failed to read '{}'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 free_block_count = GetFreeBlockCount(*data);
|
||||
const u32 num_blocks = (static_cast<u32>(blocks->size()) + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
|
||||
if (GetFreeBlockCount(*data) < num_blocks)
|
||||
if (free_block_count < num_blocks)
|
||||
{
|
||||
Log_ErrorPrint("Failed to write file to memory card: insufficient free blocks");
|
||||
Error::SetStringFmt(error, "Insufficient free blocks, needs {} blocks, but only have {}.", num_blocks,
|
||||
free_block_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -748,7 +754,7 @@ bool MemoryCardImage::ImportRawSave(DataArray* data, const char* filename, const
|
|||
{
|
||||
if (!fi.deleted)
|
||||
{
|
||||
Log_ErrorFmt("Save file with the same name '{}' already exists in memory card", fi.filename);
|
||||
Error::SetStringFmt(error, "Save file with the same name '{}' already exists in memory card.", fi.filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -756,36 +762,30 @@ bool MemoryCardImage::ImportRawSave(DataArray* data, const char* filename, const
|
|||
}
|
||||
}
|
||||
|
||||
return WriteFile(data, save_name, blocks.value());
|
||||
return WriteFile(data, save_name, blocks.value(), error);
|
||||
}
|
||||
|
||||
bool MemoryCardImage::ImportSave(DataArray* data, const char* filename)
|
||||
bool MemoryCardImage::ImportSave(DataArray* data, const char* filename, Error* error)
|
||||
{
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
if (!FileSystem::StatFile(filename, &sd))
|
||||
{
|
||||
Log_ErrorFmt("Failed to stat file '{}'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the size of the actual file is valid
|
||||
if (sd.Size == 0)
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
if (!FileSystem::StatFile(filename, &sd) || sd.Size == 0)
|
||||
{
|
||||
Log_ErrorFmt("Invalid size for save file '{}'", filename);
|
||||
Error::SetStringView(error, "File does not exist, or is empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::string_view(filename).ends_with(".mcs"))
|
||||
if (StringUtil::EqualNoCase(Path::GetExtension(filename), "mcs"))
|
||||
{
|
||||
return ImportSaveWithDirectoryFrame(data, filename, sd);
|
||||
return ImportSaveWithDirectoryFrame(data, filename, sd, error);
|
||||
}
|
||||
else if (sd.Size > 0 && sd.Size < DATA_SIZE && (sd.Size % BLOCK_SIZE) == 0)
|
||||
{
|
||||
return ImportRawSave(data, filename, sd);
|
||||
return ImportRawSave(data, filename, sd, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorFmt("Unknown save format for '{}'", filename);
|
||||
Error::SetStringView(error, "Unknown save format.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "common/bitfield.h"
|
||||
#include "controller.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
namespace MemoryCardImage {
|
||||
enum : u32
|
||||
{
|
||||
|
@ -50,12 +50,12 @@ struct FileInfo
|
|||
bool IsValid(const DataArray& data);
|
||||
u32 GetFreeBlockCount(const DataArray& data);
|
||||
std::vector<FileInfo> EnumerateFiles(const DataArray& data, bool include_deleted);
|
||||
bool ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer);
|
||||
bool WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer);
|
||||
bool ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer, Error* error);
|
||||
bool WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer, Error* error);
|
||||
bool DeleteFile(DataArray* data, const FileInfo& fi, bool clear_sectors);
|
||||
bool UndeleteFile(DataArray* data, const FileInfo& fi);
|
||||
bool ImportCard(DataArray* data, const char* filename);
|
||||
bool ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data);
|
||||
bool ExportSave(DataArray* data, const FileInfo& fi, const char* filename);
|
||||
bool ImportSave(DataArray* data, const char* filename);
|
||||
bool ImportCard(DataArray* data, const char* filename, Error* error);
|
||||
bool ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data, Error* error);
|
||||
bool ExportSave(DataArray* data, const FileInfo& fi, const char* filename, Error* error);
|
||||
bool ImportSave(DataArray* data, const char* filename, Error* error);
|
||||
} // namespace MemoryCardImage
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "core/settings.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/path.h"
|
||||
#include "common/string_util.h"
|
||||
|
@ -424,16 +425,23 @@ void MemoryCardEditorWindow::doCopyFile()
|
|||
return;
|
||||
}
|
||||
|
||||
Error error;
|
||||
std::vector<u8> buffer;
|
||||
if (!MemoryCardImage::ReadFile(src->data, *fi, &buffer))
|
||||
if (!MemoryCardImage::ReadFile(src->data, *fi, &buffer, &error))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to read file %1").arg(QString::fromStdString(fi->filename)));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to read file %1:\n%2")
|
||||
.arg(QString::fromStdString(fi->filename))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MemoryCardImage::WriteFile(&dst->data, fi->filename, buffer))
|
||||
if (!MemoryCardImage::WriteFile(&dst->data, fi->filename, buffer, &error))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to write file %1").arg(QString::fromStdString(fi->filename)));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to write file %1:\n%2")
|
||||
.arg(QString::fromStdString(fi->filename))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -497,11 +505,13 @@ void MemoryCardEditorWindow::doExportSaveFile()
|
|||
if (!fi)
|
||||
return;
|
||||
|
||||
if (!MemoryCardImage::ExportSave(&card->data, *fi, filename.toStdString().c_str()))
|
||||
Error error;
|
||||
if (!MemoryCardImage::ExportSave(&card->data, *fi, filename.toStdString().c_str(), &error))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("Failed to export save file %1. Check the log for more details.").arg(QString::fromStdString(fi->filename)));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to export save file %1:\n%2")
|
||||
.arg(QString::fromStdString(fi->filename))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -515,10 +525,14 @@ void MemoryCardEditorWindow::importCard(Card* card)
|
|||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
Error error;
|
||||
std::unique_ptr<MemoryCardImage::DataArray> temp = std::make_unique<MemoryCardImage::DataArray>();
|
||||
if (!MemoryCardImage::ImportCard(temp.get(), filename.toStdString().c_str()))
|
||||
if (!MemoryCardImage::ImportCard(temp.get(), filename.toStdString().c_str(), &error))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to import memory card. The log may contain more information."));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to import memory card from %1:\n%2")
|
||||
.arg(QFileInfo(filename).fileName())
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -557,16 +571,18 @@ void MemoryCardEditorWindow::formatCard(Card* card)
|
|||
void MemoryCardEditorWindow::importSaveFile(Card* card)
|
||||
{
|
||||
QString filename = QDir::toNativeSeparators(
|
||||
QFileDialog::getOpenFileName(this, tr("Select Import Save File"), QString(), tr(SINGLE_SAVEFILE_FILTER)));
|
||||
QFileDialog::getOpenFileName(this, tr("Select Save File"), QString(), tr(SINGLE_SAVEFILE_FILTER)));
|
||||
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
if (!MemoryCardImage::ImportSave(&card->data, filename.toStdString().c_str()))
|
||||
Error error;
|
||||
if (!MemoryCardImage::ImportSave(&card->data, filename.toStdString().c_str(), &error))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to import save. Check if there is enough room on the memory card or if an "
|
||||
"existing save with the same name already exists."));
|
||||
tr("Failed to import save from %1:\n%2")
|
||||
.arg(QFileInfo(filename).fileName())
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue