From 11dcba1b68ee2d37463efc59a1fce9b13134df0d Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 19 Mar 2021 01:52:00 +1000 Subject: [PATCH] CDImage: Use Error class for complex errors --- src/common/cd_image.cpp | 14 +++---- src/common/cd_image.h | 18 +++++---- src/common/cd_image_bin.cpp | 11 ++++-- src/common/cd_image_chd.cpp | 39 ++++++++++++++++-- src/common/cd_image_cue.cpp | 35 +++++++++++++--- src/common/cd_image_ecm.cpp | 30 ++++++++++++-- src/common/cd_image_mds.cpp | 44 ++++++++++++++++++--- src/common/cd_image_pbp.cpp | 42 ++++++++++++++++---- src/common/common.vcxproj | 2 + src/common/common.vcxproj.filters | 2 + src/core/system.cpp | 33 ++++++++++------ src/duckstation-qt/gamepropertiesdialog.cpp | 4 +- src/frontend-common/cheevos.cpp | 4 +- src/frontend-common/game_list.cpp | 4 +- 14 files changed, 219 insertions(+), 63 deletions(-) diff --git a/src/common/cd_image.cpp b/src/common/cd_image.cpp index 0ecd091d9..73e99e6d7 100644 --- a/src/common/cd_image.cpp +++ b/src/common/cd_image.cpp @@ -14,7 +14,7 @@ u32 CDImage::GetBytesPerSector(TrackMode mode) return sizes[static_cast(mode)]; } -std::unique_ptr CDImage::Open(const char* filename) +std::unique_ptr CDImage::Open(const char* filename, Common::Error* error) { const char* extension = std::strrchr(filename, '.'); if (!extension) @@ -31,28 +31,28 @@ std::unique_ptr CDImage::Open(const char* filename) if (CASE_COMPARE(extension, ".cue") == 0) { - return OpenCueSheetImage(filename); + return OpenCueSheetImage(filename, error); } else if (CASE_COMPARE(extension, ".bin") == 0 || CASE_COMPARE(extension, ".img") == 0 || CASE_COMPARE(extension, ".iso") == 0) { - return OpenBinImage(filename); + return OpenBinImage(filename, error); } else if (CASE_COMPARE(extension, ".chd") == 0) { - return OpenCHDImage(filename); + return OpenCHDImage(filename, error); } else if (CASE_COMPARE(extension, ".ecm") == 0) { - return OpenEcmImage(filename); + return OpenEcmImage(filename, error); } else if (CASE_COMPARE(extension, ".mds") == 0) { - return OpenMdsImage(filename); + return OpenMdsImage(filename, error); } else if (CASE_COMPARE(extension, ".pbp") == 0) { - return OpenPBPImage(filename); + return OpenPBPImage(filename, error); } #undef CASE_COMPARE diff --git a/src/common/cd_image.h b/src/common/cd_image.h index a5966cd7e..981bfb9d1 100644 --- a/src/common/cd_image.h +++ b/src/common/cd_image.h @@ -8,6 +8,10 @@ #include #include +namespace Common { +class Error; +} + class CDImage { public: @@ -191,13 +195,13 @@ public: static u32 GetBytesPerSector(TrackMode mode); // Opening disc image. - static std::unique_ptr Open(const char* filename); - static std::unique_ptr OpenBinImage(const char* filename); - static std::unique_ptr OpenCueSheetImage(const char* filename); - static std::unique_ptr OpenCHDImage(const char* filename); - static std::unique_ptr OpenEcmImage(const char* filename); - static std::unique_ptr OpenMdsImage(const char* filename); - static std::unique_ptr OpenPBPImage(const char* filename); + static std::unique_ptr Open(const char* filename, Common::Error* error); + static std::unique_ptr OpenBinImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenCueSheetImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenCHDImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenEcmImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenMdsImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenPBPImage(const char* filename, Common::Error* error); static std::unique_ptr CreateMemoryImage(CDImage* image, ProgressCallback* progress = ProgressCallback::NullProgressCallback); diff --git a/src/common/cd_image_bin.cpp b/src/common/cd_image_bin.cpp index 6cc9cef36..abd75d91b 100644 --- a/src/common/cd_image_bin.cpp +++ b/src/common/cd_image_bin.cpp @@ -1,5 +1,6 @@ #include "cd_image.h" #include "cd_subchannel_replacement.h" +#include "error.h" #include "file_system.h" #include "log.h" #include @@ -11,7 +12,7 @@ public: CDImageBin(); ~CDImageBin() override; - bool Open(const char* filename); + bool Open(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -34,13 +35,15 @@ CDImageBin::~CDImageBin() std::fclose(m_fp); } -bool CDImageBin::Open(const char* filename) +bool CDImageBin::Open(const char* filename, Common::Error* error) { m_filename = filename; m_fp = FileSystem::OpenCFile(filename, "rb"); if (!m_fp) { Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno); + if (error) + error->SetErrno(errno); return false; } @@ -130,10 +133,10 @@ bool CDImageBin::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i return true; } -std::unique_ptr CDImage::OpenBinImage(const char* filename) +std::unique_ptr CDImage::OpenBinImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->Open(filename)) + if (!image->Open(filename, error)) return {}; return image; diff --git a/src/common/cd_image_chd.cpp b/src/common/cd_image_chd.cpp index eae155555..552d0338a 100644 --- a/src/common/cd_image_chd.cpp +++ b/src/common/cd_image_chd.cpp @@ -7,6 +7,7 @@ #include "cd_image.h" #include "cd_subchannel_replacement.h" #include "cpu_detect.h" +#include "error.h" #include "file_system.h" #include "libchdr/chd.h" #include "log.h" @@ -46,7 +47,7 @@ public: CDImageCHD(); ~CDImageCHD() override; - bool Open(const char* filename); + bool Open(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -84,13 +85,16 @@ CDImageCHD::~CDImageCHD() std::fclose(m_fp); } -bool CDImageCHD::Open(const char* filename) +bool CDImageCHD::Open(const char* filename, Common::Error* error) { Assert(!m_fp); m_fp = FileSystem::OpenCFile(filename, "rb"); if (!m_fp) { Log_ErrorPrintf("Failed to open CHD '%s': errno %d", filename, errno); + if (error) + error->SetErrno(errno); + return false; } @@ -98,6 +102,9 @@ bool CDImageCHD::Open(const char* filename) if (err != CHDERR_NONE) { Log_ErrorPrintf("Failed to open CHD '%s': %s", filename, chd_error_string(err)); + if (error) + error->SetMessage(chd_error_string(err)); + return false; } @@ -106,6 +113,9 @@ bool CDImageCHD::Open(const char* filename) if ((m_hunk_size % CHD_CD_SECTOR_DATA_SIZE) != 0) { Log_ErrorPrintf("Hunk size (%u) is not a multiple of %u", m_hunk_size, CHD_CD_SECTOR_DATA_SIZE); + if (error) + error->SetFormattedMessage("Hunk size (%u) is not a multiple of %u", m_hunk_size, CHD_CD_SECTOR_DATA_SIZE); + return false; } @@ -136,6 +146,9 @@ bool CDImageCHD::Open(const char* filename) &pregap_frames, pgtype_str, pgsub_str, &postgap_frames) != 8) { Log_ErrorPrintf("Invalid track v2 metadata: '%s'", metadata_str); + if (error) + error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str); + return false; } } @@ -153,6 +166,9 @@ bool CDImageCHD::Open(const char* filename) if (std::sscanf(metadata_str, CDROM_TRACK_METADATA_FORMAT, &track_num, type_str, subtype_str, &frames) != 4) { Log_ErrorPrintf("Invalid track metadata: '%s'", metadata_str); + if (error) + error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str); + return false; } } @@ -161,6 +177,12 @@ bool CDImageCHD::Open(const char* filename) { Log_ErrorPrintf("Incorrect track number at index %d, expected %d got %d", num_tracks, (num_tracks + 1), track_num); + if (error) + { + error->SetFormattedMessage("Incorrect track number at index %d, expected %d got %d", num_tracks, + (num_tracks + 1), track_num); + } + return false; } @@ -168,6 +190,9 @@ bool CDImageCHD::Open(const char* filename) if (!mode.has_value()) { Log_ErrorPrintf("Invalid track mode: '%s'", type_str); + if (error) + error->SetFormattedMessage("Invalid track mode: '%s'", type_str); + return false; } @@ -198,6 +223,9 @@ bool CDImageCHD::Open(const char* filename) if (pregap_frames > frames) { Log_ErrorPrintf("Pregap length %u exceeds track length %u", pregap_frames, frames); + if (error) + error->SetFormattedMessage("Pregap length %u exceeds track length %u", pregap_frames, frames); + return false; } @@ -242,6 +270,9 @@ bool CDImageCHD::Open(const char* filename) if (m_tracks.empty()) { Log_ErrorPrintf("File '%s' contains no tracks", filename); + if (error) + error->SetFormattedMessage("File '%s' contains no tracks", filename); + return false; } @@ -343,10 +374,10 @@ bool CDImageCHD::ReadHunk(u32 hunk_index) return true; } -std::unique_ptr CDImage::OpenCHDImage(const char* filename) +std::unique_ptr CDImage::OpenCHDImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->Open(filename)) + if (!image->Open(filename, error)) return {}; return image; diff --git a/src/common/cd_image_cue.cpp b/src/common/cd_image_cue.cpp index ba27c6ada..4d484b1ad 100644 --- a/src/common/cd_image_cue.cpp +++ b/src/common/cd_image_cue.cpp @@ -1,6 +1,7 @@ #include "assert.h" #include "cd_image.h" #include "cd_subchannel_replacement.h" +#include "error.h" #include "file_system.h" #include "log.h" #include @@ -15,7 +16,7 @@ public: CDImageCueSheet(); ~CDImageCueSheet() override; - bool OpenAndParse(const char* filename); + bool OpenAndParse(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -45,12 +46,15 @@ CDImageCueSheet::~CDImageCueSheet() cd_delete(m_cd); } -bool CDImageCueSheet::OpenAndParse(const char* filename) +bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error) { std::optional cuesheet_string = FileSystem::ReadFileToString(filename); if (!cuesheet_string.has_value()) { Log_ErrorPrintf("Failed to open cuesheet '%s': errno %d", filename, errno); + if (error) + error->SetErrno(errno); + return false; } @@ -62,6 +66,9 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) if (!m_cd) { Log_ErrorPrintf("Failed to parse cuesheet '%s'", filename); + if (error) + error->SetMessage("Failed to parse cuesheet"); + return false; } @@ -80,6 +87,9 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) if (!track || !track_get_filename(track)) { Log_ErrorPrintf("Track/filename missing for track %d", track_num); + if (error) + error->SetFormattedMessage("Track/filename missing for track %d", track_num); + return false; } @@ -115,6 +125,12 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) { Log_ErrorPrintf("Failed to open track filename '%s' (from '%s' and '%s'): errno %d", track_full_filename.c_str(), track_filename.c_str(), filename, errno); + if (error) + { + error->SetFormattedMessage("Failed to open track filename '%s' (from '%s' and '%s'): errno %d", + track_full_filename.c_str(), track_filename.c_str(), filename, errno); + } + return false; } @@ -142,8 +158,13 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) file_size /= track_sector_size; if (track_start >= file_size) { - Log_ErrorPrintf("Failed to open track %u in '%s': track start is out of range (%ld vs %ld)", track_num, filename, - track_start, file_size); + Log_ErrorPrintf("Failed to open track %u in '%s': track start is out of range (%ld vs %ld)", track_num, + filename, track_start, file_size); + if (error) + { + error->SetFormattedMessage("Failed to open track %u in '%s': track start is out of range (%ld vs %ld)", + track_num, filename, track_start, file_size); + } return false; } @@ -243,6 +264,8 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) if (m_tracks.empty()) { Log_ErrorPrintf("File '%s' contains no tracks", filename); + if (error) + error->SetFormattedMessage("File '%s' contains no tracks", filename); return false; } @@ -291,10 +314,10 @@ bool CDImageCueSheet::ReadSectorFromIndex(void* buffer, const Index& index, LBA return true; } -std::unique_ptr CDImage::OpenCueSheetImage(const char* filename) +std::unique_ptr CDImage::OpenCueSheetImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->OpenAndParse(filename)) + if (!image->OpenAndParse(filename, error)) return {}; return image; diff --git a/src/common/cd_image_ecm.cpp b/src/common/cd_image_ecm.cpp index d00d026e2..6a2e3ce76 100644 --- a/src/common/cd_image_ecm.cpp +++ b/src/common/cd_image_ecm.cpp @@ -1,6 +1,7 @@ #include "assert.h" #include "cd_image.h" #include "cd_subchannel_replacement.h" +#include "error.h" #include "file_system.h" #include "log.h" #include @@ -161,7 +162,7 @@ public: CDImageEcm(); ~CDImageEcm() override; - bool Open(const char* filename); + bool Open(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -221,13 +222,16 @@ CDImageEcm::~CDImageEcm() std::fclose(m_fp); } -bool CDImageEcm::Open(const char* filename) +bool CDImageEcm::Open(const char* filename, Common::Error* error) { m_filename = filename; m_fp = FileSystem::OpenCFile(filename, "rb"); if (!m_fp) { Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno); + if (error) + error->SetErrno(errno); + return false; } @@ -236,6 +240,9 @@ bool CDImageEcm::Open(const char* filename) header[3] != 0) { Log_ErrorPrintf("Failed to read/invalid header"); + if (error) + error->SetMessage("Failed to read/invalid header"); + return false; } @@ -250,6 +257,9 @@ bool CDImageEcm::Open(const char* filename) if (bits == EOF) { Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size()); + if (error) + error->SetFormattedMessage("Unexpected EOF after %zu chunks", m_data_map.size()); + return false; } @@ -263,6 +273,9 @@ bool CDImageEcm::Open(const char* filename) if (bits == EOF) { Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size()); + if (error) + error->SetFormattedMessage("Unexpected EOF after %zu chunks", m_data_map.size()); + return false; } @@ -280,6 +293,9 @@ bool CDImageEcm::Open(const char* filename) if (count >= 0x80000000u) { Log_ErrorPrintf("Corrupted header after %zu chunks", m_data_map.size()); + if (error) + error->SetFormattedMessage("Corrupted header after %zu chunks", m_data_map.size()); + return false; } @@ -309,6 +325,9 @@ bool CDImageEcm::Open(const char* filename) if (std::fseek(m_fp, file_offset, SEEK_SET) != 0) { Log_ErrorPrintf("Failed to seek to offset %u after %zu chunks", file_offset, m_data_map.size()); + if (error) + error->SetFormattedMessage("Failed to seek to offset %u after %zu chunks", file_offset, m_data_map.size()); + return false; } } @@ -316,6 +335,9 @@ bool CDImageEcm::Open(const char* filename) if (m_data_map.empty()) { Log_ErrorPrintf("No data in image '%s'", filename); + if (error) + error->SetFormattedMessage("No data in image '%s'", filename); + return false; } @@ -501,10 +523,10 @@ bool CDImageEcm::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i return true; } -std::unique_ptr CDImage::OpenEcmImage(const char* filename) +std::unique_ptr CDImage::OpenEcmImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->Open(filename)) + if (!image->Open(filename, error)) return {}; return image; diff --git a/src/common/cd_image_mds.cpp b/src/common/cd_image_mds.cpp index e589ec48b..3bbb188c8 100644 --- a/src/common/cd_image_mds.cpp +++ b/src/common/cd_image_mds.cpp @@ -1,6 +1,7 @@ #include "assert.h" #include "cd_image.h" #include "cd_subchannel_replacement.h" +#include "error.h" #include "file_system.h" #include "log.h" #include @@ -34,7 +35,7 @@ public: CDImageMds(); ~CDImageMds() override; - bool OpenAndParse(const char* filename); + bool OpenAndParse(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -56,12 +57,15 @@ CDImageMds::~CDImageMds() std::fclose(m_mdf_file); } -bool CDImageMds::OpenAndParse(const char* filename) +bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error) { std::FILE* mds_fp = FileSystem::OpenCFile(filename, "rb"); if (!mds_fp) { Log_ErrorPrintf("Failed to open mds '%s': errno %d", filename, errno); + if (error) + error->SetErrno(errno); + return false; } @@ -70,6 +74,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (!mds_data_opt.has_value() || mds_data_opt->size() < 0x54) { Log_ErrorPrintf("Failed to read mds file '%s'", filename); + if (error) + error->SetFormattedMessage("Failed to read mds file '%s'", filename); + return false; } @@ -78,6 +85,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (!m_mdf_file) { Log_ErrorPrintf("Failed to open mdf file '%s': errno %d", mdf_filename.c_str(), errno); + if (error) + error->SetFormattedMessage("Failed to open mdf file '%s': errno %d", mdf_filename.c_str(), errno); + return false; } @@ -86,6 +96,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (std::memcmp(&mds[0], expected_signature, sizeof(expected_signature) - 1) != 0) { Log_ErrorPrintf("Incorrect signature in '%s'", filename); + if (error) + error->SetFormattedMessage("Incorrect signature in '%s'", filename); + return false; } @@ -94,6 +107,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if ((session_offset + 24) > mds.size()) { Log_ErrorPrintf("Invalid session offset in '%s'", filename); + if (error) + error->SetFormattedMessage("Invalid session offset in '%s'", filename); + return false; } @@ -104,6 +120,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (track_count > 99 || track_offset >= mds.size()) { Log_ErrorPrintf("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename); + if (error) + error->SetFormattedMessage("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename); + return false; } @@ -122,6 +141,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if ((track_offset + sizeof(TrackEntry)) > mds.size()) { Log_ErrorPrintf("End of file in '%s' at track %u", filename, track_number); + if (error) + error->SetFormattedMessage("End of file in '%s' at track %u", filename, track_number); + return false; } @@ -130,9 +152,12 @@ bool CDImageMds::OpenAndParse(const char* filename) if (PackedBCDToBinary(track.track_number) != track_number) { Log_ErrorPrintf("Unexpected track number 0x%02X in track %u", track.track_number, track_number); + if (error) + error->SetFormattedMessage("Unexpected track number 0x%02X in track %u", track.track_number, track_number); + return false; } - + const bool contains_subchannel = (track.has_subchannel_data != 0); const u32 track_sector_size = (contains_subchannel ? 2448 : RAW_SECTOR_SIZE); const TrackMode mode = (track.track_type == 0xA9) ? TrackMode::Audio : TrackMode::Mode2Raw; @@ -140,6 +165,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if ((track.extra_offset + sizeof(u32) + sizeof(u32)) > mds.size()) { Log_ErrorPrintf("Invalid extra offset %u in track %u", track.extra_offset, track_number); + if (error) + error->SetFormattedMessage("Invalid extra offset %u in track %u", track.extra_offset, track_number); + return false; } @@ -162,6 +190,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (track_pregap > track_start_lba) { Log_ErrorPrintf("Track pregap %u is too large for start lba %u", track_pregap, track_start_lba); + if (error) + error->SetFormattedMessage("Track pregap %u is too large for start lba %u", track_pregap, track_start_lba); + return false; } @@ -210,6 +241,9 @@ bool CDImageMds::OpenAndParse(const char* filename) if (m_tracks.empty()) { Log_ErrorPrintf("File '%s' contains no tracks", filename); + if (error) + error->SetFormattedMessage("File '%s' contains no tracks", filename); + return false; } @@ -257,10 +291,10 @@ bool CDImageMds::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i return true; } -std::unique_ptr CDImage::OpenMdsImage(const char* filename) +std::unique_ptr CDImage::OpenMdsImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->OpenAndParse(filename)) + if (!image->OpenAndParse(filename, error)) return {}; return image; diff --git a/src/common/cd_image_pbp.cpp b/src/common/cd_image_pbp.cpp index 18aadfd88..dfdb79b74 100644 --- a/src/common/cd_image_pbp.cpp +++ b/src/common/cd_image_pbp.cpp @@ -1,5 +1,6 @@ #include "cd_image.h" #include "cd_subchannel_replacement.h" +#include "error.h" #include "file_system.h" #include "log.h" #include "pbp_types.h" @@ -18,7 +19,7 @@ public: CDImagePBP() = default; ~CDImagePBP() override; - bool Open(const char* filename); + bool Open(const char* filename, Common::Error* error); bool ReadSubChannelQ(SubChannelQ* subq) override; bool HasNonStandardSubchannel() const override; @@ -45,7 +46,7 @@ private: bool LoadSFOIndexTable(); bool LoadSFOTable(); - bool IsValidEboot(); + bool IsValidEboot(Common::Error* error); bool InitDecompressionStream(); bool DecompressBlock(BlockInfo block_info); @@ -257,7 +258,7 @@ bool CDImagePBP::LoadSFOTable() return true; } -bool CDImagePBP::IsValidEboot() +bool CDImagePBP::IsValidEboot(Common::Error* error) { // Check some fields to make sure this is a valid PS1 EBOOT.PBP @@ -268,12 +269,16 @@ bool CDImagePBP::IsValidEboot() if (!std::holds_alternative(data_value) || std::get(data_value) != 1) { Log_ErrorPrint("Invalid BOOTABLE value"); + if (error) + error->SetMessage("Invalid BOOTABLE value"); return false; } } else { Log_ErrorPrint("No BOOTABLE value found"); + if (error) + error->SetMessage("No BOOTABLE value found"); return false; } @@ -284,19 +289,23 @@ bool CDImagePBP::IsValidEboot() if (!std::holds_alternative(data_value) || std::get(data_value) != "ME") { Log_ErrorPrint("Invalid CATEGORY value"); + if (error) + error->SetMessage("Invalid CATEGORY value"); return false; } } else { Log_ErrorPrint("No CATEGORY value found"); + if (error) + error->SetMessage("No CATEGORY value found"); return false; } return true; } -bool CDImagePBP::Open(const char* filename) +bool CDImagePBP::Open(const char* filename, Common::Error* error) { if (!EndianHelper::HostIsLittleEndian()) { @@ -306,7 +315,12 @@ bool CDImagePBP::Open(const char* filename) m_file = FileSystem::OpenCFile(filename, "rb"); if (!m_file) + { + if (error) + error->SetErrno(errno); + return false; + } m_filename = filename; @@ -314,6 +328,8 @@ bool CDImagePBP::Open(const char* filename) if (!LoadPBPHeader()) { Log_ErrorPrint("Failed to load PBP header"); + if (error) + error->SetMessage("Failed to load PBP header"); return false; } @@ -321,6 +337,8 @@ bool CDImagePBP::Open(const char* filename) if (!LoadSFOHeader()) { Log_ErrorPrint("Failed to load SFO header"); + if (error) + error->SetMessage("Failed to load SFO header"); return false; } @@ -328,6 +346,8 @@ bool CDImagePBP::Open(const char* filename) if (!LoadSFOIndexTable()) { Log_ErrorPrint("Failed to load SFO index table"); + if (error) + error->SetMessage("Failed to load SFO index table"); return false; } @@ -335,11 +355,13 @@ bool CDImagePBP::Open(const char* filename) if (!LoadSFOTable()) { Log_ErrorPrint("Failed to load SFO table"); + if (error) + error->SetMessage("Failed to load SFO table"); return false; } // Since PBP files can store things that aren't PS1 CD images, make sure we're loading the right kind - if (!IsValidEboot()) + if (!IsValidEboot(error)) { Log_ErrorPrint("Couldn't validate EBOOT"); return false; @@ -372,6 +394,9 @@ bool CDImagePBP::Open(const char* filename) if (disc_table[0] == 0x44475000) // "\0PGD" { Log_ErrorPrint("Encrypted PBP images are not supported"); + if (error) + error->SetMessage("Encrypted PBP images are not supported"); + return false; } @@ -421,6 +446,9 @@ bool CDImagePBP::Open(const char* filename) if (pgd_magic == 0x44475000) // "\0PGD" { Log_ErrorPrint("Encrypted PBP images are not supported"); + if (error) + error->SetMessage("Encrypted PBP images are not supported"); + return false; } @@ -739,10 +767,10 @@ void CDImagePBP::PrintSFOTable(const SFOTable& sfo_table) } #endif -std::unique_ptr CDImage::OpenPBPImage(const char* filename) +std::unique_ptr CDImage::OpenPBPImage(const char* filename, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->Open(filename)) + if (!image->Open(filename, error)) return {}; return image; diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 8ca686f01..6aa37d67b 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -68,6 +68,7 @@ + @@ -142,6 +143,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 5d941ccc6..64a72cf9b 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -111,6 +111,7 @@ + @@ -214,6 +215,7 @@ + diff --git a/src/core/system.cpp b/src/core/system.cpp index ad421801c..3c0c0a44a 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -4,6 +4,7 @@ #include "cdrom.h" #include "cheats.h" #include "common/audio_stream.h" +#include "common/error.h" #include "common/file_system.h" #include "common/iso_reader.h" #include "common/log.h" @@ -66,7 +67,7 @@ static bool LoadEXE(const char* filename); static bool SetExpansionROM(const char* filename); /// Opens CD image, preloading if needed. -static std::unique_ptr OpenCDImage(const char* path, bool force_preload); +static std::unique_ptr OpenCDImage(const char* path, Common::Error* error, bool force_preload); static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display); static bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display); @@ -388,7 +389,7 @@ std::string_view GetTitleForPath(const char* path) std::string GetGameCodeForPath(const char* image_path, bool fallback_to_hash) { - std::unique_ptr cdi = CDImage::Open(image_path); + std::unique_ptr cdi = CDImage::Open(image_path, nullptr); if (!cdi) return {}; @@ -656,7 +657,7 @@ std::optional GetRegionForPath(const char* image_path) else if (IsPsfFileName(image_path)) return GetRegionForPsf(image_path); - std::unique_ptr cdi = CDImage::Open(image_path); + std::unique_ptr cdi = CDImage::Open(image_path, nullptr); if (!cdi) return {}; @@ -704,9 +705,9 @@ bool RecreateGPU(GPURenderer renderer, bool update_display /* = true*/) return true; } -std::unique_ptr OpenCDImage(const char* path, bool force_preload) +std::unique_ptr OpenCDImage(const char* path, Common::Error* error, bool force_preload) { - std::unique_ptr media = CDImage::Open(path); + std::unique_ptr media = CDImage::Open(path, error); if (!media) return {}; @@ -796,12 +797,14 @@ bool Boot(const SystemBootParameters& params) playlist_index = 0; } + Common::Error error; const std::string& media_path = s_media_playlist[playlist_index]; Log_InfoPrintf("Loading CD image '%s' from playlist index %u...", media_path.c_str(), playlist_index); - media = OpenCDImage(media_path.c_str(), params.load_image_to_ram); + media = OpenCDImage(media_path.c_str(), &error, params.load_image_to_ram); if (!media) { - g_host_interface->ReportFormattedError("Failed to load CD image '%s'", params.filename.c_str()); + g_host_interface->ReportFormattedError("Failed to load CD image '%s': %s", params.filename.c_str(), + error.GetCodeAndMessage().GetCharArray()); Shutdown(); return false; } @@ -1215,22 +1218,24 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer, bool update_di } else { - media = OpenCDImage(media_filename.c_str(), false); + Common::Error error; + media = OpenCDImage(media_filename.c_str(), &error, false); if (!media) { if (old_media) { g_host_interface->AddFormattedOSDMessage( 30.0f, - g_host_interface->TranslateString("OSDMessage", "Failed to open CD image from save state: '%s'. Using " + g_host_interface->TranslateString("OSDMessage", "Failed to open CD image from save state '%s': %s. Using " "existing image '%s', this may result in instability."), - media_filename.c_str(), old_media->GetFileName().c_str()); + media_filename.c_str(), error.GetCodeAndMessage().GetCharArray(), old_media->GetFileName().c_str()); media = std::move(old_media); } else { g_host_interface->ReportFormattedError( - g_host_interface->TranslateString("System", "Failed to open CD image from save state: '%s'."), + g_host_interface->TranslateString("System", "Failed to open CD image from save state '%s': %s.", + error.GetCodeAndMessage().GetCharArray()), media_filename.c_str()); return false; } @@ -1965,11 +1970,13 @@ std::string GetMediaFileName() bool InsertMedia(const char* path) { - std::unique_ptr image = OpenCDImage(path, false); + Common::Error error; + std::unique_ptr image = OpenCDImage(path, &error, false); if (!image) { g_host_interface->AddFormattedOSDMessage( - 10.0f, g_host_interface->TranslateString("OSDMessage", "Failed to open disc image '%s'."), path); + 10.0f, g_host_interface->TranslateString("OSDMessage", "Failed to open disc image '%s': %s."), path, + error.GetCodeAndMessage().GetCharArray()); return false; } diff --git a/src/duckstation-qt/gamepropertiesdialog.cpp b/src/duckstation-qt/gamepropertiesdialog.cpp index 814028176..c6451f153 100644 --- a/src/duckstation-qt/gamepropertiesdialog.cpp +++ b/src/duckstation-qt/gamepropertiesdialog.cpp @@ -224,7 +224,7 @@ void GamePropertiesDialog::populateTracksInfo(const std::string& image_path) m_ui.tracks->clearContents(); m_path = image_path; - std::unique_ptr image = CDImage::Open(image_path.c_str()); + std::unique_ptr image = CDImage::Open(image_path.c_str(), nullptr); if (!image) return; @@ -860,7 +860,7 @@ void GamePropertiesDialog::computeTrackHashes() if (m_path.empty()) return; - std::unique_ptr image = CDImage::Open(m_path.c_str()); + std::unique_ptr image = CDImage::Open(m_path.c_str(), nullptr); if (!image) return; diff --git a/src/frontend-common/cheevos.cpp b/src/frontend-common/cheevos.cpp index 27575100a..18e62e27a 100644 --- a/src/frontend-common/cheevos.cpp +++ b/src/frontend-common/cheevos.cpp @@ -816,7 +816,7 @@ void GameChanged() if (path.empty() || s_game_path == path) return; - std::unique_ptr cdi = CDImage::Open(path.c_str()); + std::unique_ptr cdi = CDImage::Open(path.c_str(), nullptr); if (!cdi) { Log_ErrorPrintf("Failed to open temporary CD image '%s'", path.c_str()); @@ -855,7 +855,7 @@ void GameChanged(const std::string& path, CDImage* image) if (playlist_index > 0 && playlist_index < playlist_count) { const std::string& first_disc_path(System::GetMediaPlaylistPath(0)); - std::unique_ptr first_disc_image(CDImage::Open(first_disc_path.c_str())); + std::unique_ptr first_disc_image(CDImage::Open(first_disc_path.c_str(), nullptr)); if (first_disc_image) { Log_InfoPrintf("Using first disc '%s' from playlist (currently '%s')", first_disc_path.c_str(), path.c_str()); diff --git a/src/frontend-common/game_list.cpp b/src/frontend-common/game_list.cpp index a45592ceb..820841825 100644 --- a/src/frontend-common/game_list.cpp +++ b/src/frontend-common/game_list.cpp @@ -168,7 +168,7 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry) for (size_t i = 0; i < entries.size(); i++) { - std::unique_ptr entry_image = CDImage::Open(entries[i].c_str()); + std::unique_ptr entry_image = CDImage::Open(entries[i].c_str(), nullptr); if (!entry_image) { Log_ErrorPrintf("Failed to open entry %zu ('%s') in playlist %s", i, entries[i].c_str(), path); @@ -203,7 +203,7 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry) if (System::IsM3UFileName(path.c_str())) return GetM3UListEntry(path.c_str(), entry); - std::unique_ptr cdi = CDImage::Open(path.c_str()); + std::unique_ptr cdi = CDImage::Open(path.c_str(), nullptr); if (!cdi) return false;