MemoryCard: Purge use of ByteStream

This commit is contained in:
Stenzek 2024-07-28 23:28:13 +10:00
parent b5009da2bc
commit dd8bf2c9d9
No known key found for this signature in database
8 changed files with 85 additions and 72 deletions

View file

@ -1735,8 +1735,9 @@ std::string GameList::GetGameIconPath(std::string_view serial, std::string_view
StringUtil::Strlcpy(serial_entry->serial, index_serial.view(), sizeof(serial_entry->serial)); StringUtil::Strlcpy(serial_entry->serial, index_serial.view(), sizeof(serial_entry->serial));
// Try extracting an icon. // Try extracting an icon.
Error error;
MemoryCardImage::DataArray data; MemoryCardImage::DataArray data;
if (MemoryCardImage::LoadFromFile(&data, memcard_path.c_str())) if (MemoryCardImage::LoadFromFile(&data, memcard_path.c_str(), &error))
{ {
std::vector<MemoryCardImage::FileInfo> files = MemoryCardImage::EnumerateFiles(data, false); std::vector<MemoryCardImage::FileInfo> files = MemoryCardImage::EnumerateFiles(data, false);
if (!files.empty()) if (!files.empty())
@ -1760,6 +1761,10 @@ std::string GameList::GetGameIconPath(std::string_view serial, std::string_view
} }
} }
} }
else
{
ERROR_LOG("Failed to load memory card '{}': {}", Path::GetFileName(memcard_path), error.GetDescription());
}
UpdateMemcardTimestampCache(*serial_entry); UpdateMemcardTimestampCache(*serial_entry);
return ret; return ret;

View file

@ -10,6 +10,7 @@
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/byte_stream.h" #include "common/byte_stream.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -298,11 +299,20 @@ std::unique_ptr<MemoryCard> MemoryCard::Open(std::string_view filename)
{ {
std::unique_ptr<MemoryCard> mc = std::make_unique<MemoryCard>(); std::unique_ptr<MemoryCard> mc = std::make_unique<MemoryCard>();
mc->m_filename = filename; mc->m_filename = filename;
if (!mc->LoadFromFile()) [[unlikely]]
Error error;
if (!FileSystem::FileExists(mc->m_filename.c_str())) [[unlikely]]
{
Host::AddIconOSDMessage(fmt::format("memory_card_{}", filename), ICON_FA_SD_CARD,
fmt::format(TRANSLATE_FS("OSDMessage", "Memory card '{}' does not exist, creating."),
Path::GetFileName(filename), Host::OSD_INFO_DURATION));
mc->Format();
mc->SaveIfChanged(true);
}
else if (!MemoryCardImage::LoadFromFile(&mc->m_data, mc->m_filename.c_str(), &error)) [[unlikely]]
{ {
INFO_LOG("Memory card at '{}' could not be read, formatting.", mc->m_filename);
Host::AddIconOSDMessage(fmt::format("memory_card_{}", filename), ICON_FA_SD_CARD, Host::AddIconOSDMessage(fmt::format("memory_card_{}", filename), ICON_FA_SD_CARD,
fmt::format(TRANSLATE_FS("OSDMessage", "Memory card '{}' could not be read, formatting."), fmt::format(TRANSLATE_FS("OSDMessage", "Memory card '{}' could not be read: {}"),
Path::GetFileName(filename), Host::OSD_INFO_DURATION)); Path::GetFileName(filename), Host::OSD_INFO_DURATION));
mc->Format(); mc->Format();
} }
@ -316,11 +326,6 @@ void MemoryCard::Format()
m_changed = true; m_changed = true;
} }
bool MemoryCard::LoadFromFile()
{
return MemoryCardImage::LoadFromFile(&m_data, m_filename.c_str());
}
bool MemoryCard::SaveIfChanged(bool display_osd_message) bool MemoryCard::SaveIfChanged(bool display_osd_message)
{ {
m_save_event.Deactivate(); m_save_event.Deactivate();
@ -341,13 +346,16 @@ bool MemoryCard::SaveIfChanged(bool display_osd_message)
display_name = FileSystem::GetDisplayNameFromPath(m_filename); display_name = FileSystem::GetDisplayNameFromPath(m_filename);
} }
if (!MemoryCardImage::SaveToFile(m_data, m_filename.c_str())) INFO_LOG("Saving memory card to {}...", Path::GetFileTitle(m_filename));
Error error;
if (!MemoryCardImage::SaveToFile(m_data, m_filename.c_str(), &error))
{ {
if (display_osd_message) if (display_osd_message)
{ {
Host::AddIconOSDMessage( Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_SD_CARD,
std::move(osd_key), ICON_FA_SD_CARD, fmt::format(TRANSLATE_FS("OSDMessage", "Failed to save memory card to '{}': {}"),
fmt::format(TRANSLATE_FS("OSDMessage", "Failed to save memory card to '{}'."), Path::GetFileName(display_name)), Path::GetFileName(display_name), error.GetDescription()),
Host::OSD_ERROR_DURATION); Host::OSD_ERROR_DURATION);
} }

View file

@ -95,7 +95,6 @@ private:
static TickCount GetSaveDelayInTicks(); static TickCount GetSaveDelayInTicks();
bool LoadFromFile();
bool SaveIfChanged(bool display_osd_message); bool SaveIfChanged(bool display_osd_message);
void QueueFileSave(); void QueueFileSave();

View file

@ -9,7 +9,6 @@
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/byte_stream.h"
#include "common/error.h" #include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
@ -97,17 +96,21 @@ static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename,
static bool ImportRawSave(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 } // namespace MemoryCardImage
bool MemoryCardImage::LoadFromFile(DataArray* data, const char* filename) bool MemoryCardImage::LoadFromFile(DataArray* data, const char* filename, Error* error)
{ {
FILESYSTEM_STAT_DATA sd; FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(filename, "rb", error);
if (!FileSystem::StatFile(filename, &sd) || sd.Size != DATA_SIZE) if (!fp)
return false; return false;
std::unique_ptr<ByteStream> stream = ByteStream::OpenFile(filename, BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED); const s64 size = FileSystem::FSize64(fp.get());
if (!stream || stream->GetSize() != DATA_SIZE) if (size != static_cast<s64>(DATA_SIZE))
{
ERROR_LOG("Memory card {} is incorrect size (expected {} got {})", Path::GetFileName(filename),
static_cast<u32>(DATA_SIZE), size);
return false; return false;
}
const size_t num_read = stream->Read(data->data(), DATA_SIZE); const size_t num_read = std::fread(data->data(), 1, DATA_SIZE, fp.get());
if (num_read != DATA_SIZE) if (num_read != DATA_SIZE)
{ {
ERROR_LOG("Only read {} of {} sectors from '{}'", num_read / FRAME_SIZE, static_cast<u32>(NUM_FRAMES), filename); ERROR_LOG("Only read {} of {} sectors from '{}'", num_read / FRAME_SIZE, static_cast<u32>(NUM_FRAMES), filename);
@ -118,25 +121,17 @@ bool MemoryCardImage::LoadFromFile(DataArray* data, const char* filename)
return true; return true;
} }
bool MemoryCardImage::SaveToFile(const DataArray& data, const char* filename) bool MemoryCardImage::SaveToFile(const DataArray& data, const char* filename, Error* error)
{ {
std::unique_ptr<ByteStream> stream = Error local_error;
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE | if (!FileSystem::WriteAtomicRenamedFile(filename, data.data(), data.size(), error ? error : &local_error))
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED); [[unlikely]]
if (!stream)
{
ERROR_LOG("Failed to open '{}' for writing.", filename);
return false;
}
if (!stream->Write2(data.data(), DATA_SIZE) || !stream->Commit())
{ {
ERROR_LOG("Failed to write sectors to '{}'", filename); ERROR_LOG("Failed to save memory card '{}': {}", Path::GetFileName(filename),
stream->Discard(); (error ? error : &local_error)->GetDescription());
return false; return false;
} }
VERBOSE_LOG("Saved memory card to '{}'", filename);
return true; return true;
} }
@ -634,27 +629,21 @@ bool MemoryCardImage::ImportCard(DataArray* data, const char* filename, Error* e
bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char* filename, Error* error) bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char* filename, Error* error)
{ {
std::unique_ptr<ByteStream> stream = // TODO: This could be span...
ByteStream::OpenFile(filename, std::vector<u8> file_data;
BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE | if (!ReadFile(*data, fi, &file_data, error))
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED,
error);
if (!stream)
return false; return false;
DirectoryFrame* df_ptr = GetFramePtr<DirectoryFrame>(data, 0, fi.first_block); auto fp = FileSystem::CreateAtomicRenamedFile(filename, "wb", error);
std::vector<u8> header = std::vector<u8>(static_cast<size_t>(FRAME_SIZE)); if (!fp)
std::memcpy(header.data(), df_ptr, sizeof(*df_ptr));
std::vector<u8> blocks;
if (!ReadFile(*data, fi, &blocks, error))
return false; return false;
if (!stream->Write(header.data(), static_cast<u32>(header.size())) || DirectoryFrame* df_ptr = GetFramePtr<DirectoryFrame>(data, 0, fi.first_block);
!stream->Write(blocks.data(), static_cast<u32>(blocks.size())) || !stream->Commit()) if (std::fwrite(df_ptr, sizeof(DirectoryFrame), 1, fp.get()) != 1 ||
std::fwrite(file_data.data(), file_data.size(), 1, fp.get()) != 1)
{ {
Error::SetStringView(error, "Failed to write exported save."); Error::SetErrno(error, "fwrite() failed: ", errno);
stream->Discard(); FileSystem::DiscardAtomicRenamedFile(fp);
return false; return false;
} }
@ -671,15 +660,14 @@ bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char*
return false; return false;
} }
std::unique_ptr<ByteStream> stream = auto fp = FileSystem::OpenManagedCFile(filename, "rb", error);
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED, error); if (!fp)
if (!stream)
return false; return false;
DirectoryFrame df; DirectoryFrame df;
if (stream->Read(&df, FRAME_SIZE) != FRAME_SIZE) if (std::fread(&df, sizeof(df), 1, fp.get()) != 1)
{ {
Error::SetStringView(error, "Failed to read directory frame."); Error::SetErrno(error, "Failed to read directory frame: ", errno);
return false; return false;
} }
@ -691,9 +679,9 @@ bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char*
} }
std::vector<u8> blocks = std::vector<u8>(static_cast<size_t>(df.file_size)); 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) if (std::fread(blocks.data(), df.file_size, 1, fp.get()) != 1)
{ {
Error::SetStringView(error, "Failed to read block bytes."); Error::SetErrno(error, "Failed to read block bytes: ", errno);
return false; return false;
} }

View file

@ -25,8 +25,8 @@ enum : u32
using DataArray = std::array<u8, DATA_SIZE>; using DataArray = std::array<u8, DATA_SIZE>;
bool LoadFromFile(DataArray* data, const char* filename); bool LoadFromFile(DataArray* data, const char* filename, Error* error);
bool SaveToFile(const DataArray& data, const char* filename); bool SaveToFile(const DataArray& data, const char* filename, Error* error);
void Format(DataArray* data); void Format(DataArray* data);

View file

@ -33,6 +33,7 @@
#include "util/gpu_device.h" #include "util/gpu_device.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
@ -2965,9 +2966,14 @@ void MainWindow::openMemoryCardEditor(const QString& card_a_path, const QString&
tr("Memory card '%1' does not exist. Do you want to create an empty memory card?").arg(card_path), tr("Memory card '%1' does not exist. Do you want to create an empty memory card?").arg(card_path),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{ {
if (!MemoryCardEditorWindow::createMemoryCard(card_path)) Error error;
if (!MemoryCardEditorWindow::createMemoryCard(card_path, &error))
{
QMessageBox::critical(this, tr("Memory Card Not Found"), QMessageBox::critical(this, tr("Memory Card Not Found"),
tr("Failed to create memory card '%1'").arg(card_path)); tr("Failed to create memory card '%1': %2")
.arg(card_path)
.arg(QString::fromStdString(error.GetDescription())));
}
} }
} }
} }

View file

@ -96,12 +96,12 @@ bool MemoryCardEditorWindow::setCardB(const QString& path)
return true; return true;
} }
bool MemoryCardEditorWindow::createMemoryCard(const QString& path) bool MemoryCardEditorWindow::createMemoryCard(const QString& path, Error* error)
{ {
MemoryCardImage::DataArray data; MemoryCardImage::DataArray data;
MemoryCardImage::Format(&data); MemoryCardImage::Format(&data);
return MemoryCardImage::SaveToFile(data, path.toUtf8().constData()); return MemoryCardImage::SaveToFile(data, path.toUtf8().constData(), error);
} }
void MemoryCardEditorWindow::resizeEvent(QResizeEvent* ev) void MemoryCardEditorWindow::resizeEvent(QResizeEvent* ev)
@ -232,10 +232,12 @@ bool MemoryCardEditorWindow::loadCard(const QString& filename, Card* card)
return false; return false;
} }
Error error;
std::string filename_str = filename.toStdString(); std::string filename_str = filename.toStdString();
if (!MemoryCardImage::LoadFromFile(&card->data, filename_str.c_str())) if (!MemoryCardImage::LoadFromFile(&card->data, filename_str.c_str(), &error))
{ {
QMessageBox::critical(this, tr("Error"), tr("Failed to load memory card image.")); QMessageBox::critical(this, tr("Error"),
tr("Failed to load memory card: %1").arg(QString::fromStdString(error.GetDescription())));
return false; return false;
} }
@ -343,9 +345,11 @@ void MemoryCardEditorWindow::openCard(Card* card)
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
if (!MemoryCardImage::LoadFromFile(&card->data, filename.toUtf8().constData())) Error error;
if (!MemoryCardImage::LoadFromFile(&card->data, filename.toUtf8().constData(), &error))
{ {
QMessageBox::critical(this, tr("Error"), tr("Failed to load memory card image.")); QMessageBox::critical(this, tr("Error"),
tr("Failed to load memory card: %1").arg(QString::fromStdString(error.GetDescription())));
return; return;
} }
@ -368,10 +372,11 @@ void MemoryCardEditorWindow::saveCard(Card* card)
if (card->filename.empty()) if (card->filename.empty())
return; return;
if (!MemoryCardImage::SaveToFile(card->data, card->filename.c_str())) Error error;
if (!MemoryCardImage::SaveToFile(card->data, card->filename.c_str(), &error))
{ {
QMessageBox::critical(this, tr("Error"), QMessageBox::critical(this, tr("Error"),
tr("Failed to write card to '%1'").arg(QString::fromStdString(card->filename))); tr("Failed to save memory card: %1").arg(QString::fromStdString(error.GetDescription())));
return; return;
} }

View file

@ -14,6 +14,8 @@
#include <QtWidgets/QPushButton> #include <QtWidgets/QPushButton>
#include <QtWidgets/QTableWidget> #include <QtWidgets/QTableWidget>
class Error;
class MemoryCardEditorWindow : public QWidget class MemoryCardEditorWindow : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -25,7 +27,7 @@ public:
bool setCardA(const QString& path); bool setCardA(const QString& path);
bool setCardB(const QString& path); bool setCardB(const QString& path);
static bool createMemoryCard(const QString& path); static bool createMemoryCard(const QString& path, Error* error);
protected: protected:
void resizeEvent(QResizeEvent* ev); void resizeEvent(QResizeEvent* ev);