CDImage: Use Error class for complex errors

This commit is contained in:
Connor McLaughlin 2021-03-19 01:52:00 +10:00
parent 955afc3182
commit 11dcba1b68
14 changed files with 219 additions and 63 deletions

View file

@ -14,7 +14,7 @@ u32 CDImage::GetBytesPerSector(TrackMode mode)
return sizes[static_cast<u32>(mode)]; return sizes[static_cast<u32>(mode)];
} }
std::unique_ptr<CDImage> CDImage::Open(const char* filename) std::unique_ptr<CDImage> CDImage::Open(const char* filename, Common::Error* error)
{ {
const char* extension = std::strrchr(filename, '.'); const char* extension = std::strrchr(filename, '.');
if (!extension) if (!extension)
@ -31,28 +31,28 @@ std::unique_ptr<CDImage> CDImage::Open(const char* filename)
if (CASE_COMPARE(extension, ".cue") == 0) 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 || else if (CASE_COMPARE(extension, ".bin") == 0 || CASE_COMPARE(extension, ".img") == 0 ||
CASE_COMPARE(extension, ".iso") == 0) CASE_COMPARE(extension, ".iso") == 0)
{ {
return OpenBinImage(filename); return OpenBinImage(filename, error);
} }
else if (CASE_COMPARE(extension, ".chd") == 0) else if (CASE_COMPARE(extension, ".chd") == 0)
{ {
return OpenCHDImage(filename); return OpenCHDImage(filename, error);
} }
else if (CASE_COMPARE(extension, ".ecm") == 0) else if (CASE_COMPARE(extension, ".ecm") == 0)
{ {
return OpenEcmImage(filename); return OpenEcmImage(filename, error);
} }
else if (CASE_COMPARE(extension, ".mds") == 0) else if (CASE_COMPARE(extension, ".mds") == 0)
{ {
return OpenMdsImage(filename); return OpenMdsImage(filename, error);
} }
else if (CASE_COMPARE(extension, ".pbp") == 0) else if (CASE_COMPARE(extension, ".pbp") == 0)
{ {
return OpenPBPImage(filename); return OpenPBPImage(filename, error);
} }
#undef CASE_COMPARE #undef CASE_COMPARE

View file

@ -8,6 +8,10 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
namespace Common {
class Error;
}
class CDImage class CDImage
{ {
public: public:
@ -191,13 +195,13 @@ public:
static u32 GetBytesPerSector(TrackMode mode); static u32 GetBytesPerSector(TrackMode mode);
// Opening disc image. // Opening disc image.
static std::unique_ptr<CDImage> Open(const char* filename); static std::unique_ptr<CDImage> Open(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenBinImage(const char* filename); static std::unique_ptr<CDImage> OpenBinImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenCueSheetImage(const char* filename); static std::unique_ptr<CDImage> OpenCueSheetImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenCHDImage(const char* filename); static std::unique_ptr<CDImage> OpenCHDImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenEcmImage(const char* filename); static std::unique_ptr<CDImage> OpenEcmImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenMdsImage(const char* filename); static std::unique_ptr<CDImage> OpenMdsImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> OpenPBPImage(const char* filename); static std::unique_ptr<CDImage> OpenPBPImage(const char* filename, Common::Error* error);
static std::unique_ptr<CDImage> static std::unique_ptr<CDImage>
CreateMemoryImage(CDImage* image, ProgressCallback* progress = ProgressCallback::NullProgressCallback); CreateMemoryImage(CDImage* image, ProgressCallback* progress = ProgressCallback::NullProgressCallback);

View file

@ -1,5 +1,6 @@
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "log.h" #include "log.h"
#include <cerrno> #include <cerrno>
@ -11,7 +12,7 @@ public:
CDImageBin(); CDImageBin();
~CDImageBin() override; ~CDImageBin() override;
bool Open(const char* filename); bool Open(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -34,13 +35,15 @@ CDImageBin::~CDImageBin()
std::fclose(m_fp); std::fclose(m_fp);
} }
bool CDImageBin::Open(const char* filename) bool CDImageBin::Open(const char* filename, Common::Error* error)
{ {
m_filename = filename; m_filename = filename;
m_fp = FileSystem::OpenCFile(filename, "rb"); m_fp = FileSystem::OpenCFile(filename, "rb");
if (!m_fp) if (!m_fp)
{ {
Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno); Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno);
if (error)
error->SetErrno(errno);
return false; return false;
} }
@ -130,10 +133,10 @@ bool CDImageBin::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
return true; return true;
} }
std::unique_ptr<CDImage> CDImage::OpenBinImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenBinImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImageBin> image = std::make_unique<CDImageBin>(); std::unique_ptr<CDImageBin> image = std::make_unique<CDImageBin>();
if (!image->Open(filename)) if (!image->Open(filename, error))
return {}; return {};
return image; return image;

View file

@ -7,6 +7,7 @@
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "cpu_detect.h" #include "cpu_detect.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "libchdr/chd.h" #include "libchdr/chd.h"
#include "log.h" #include "log.h"
@ -46,7 +47,7 @@ public:
CDImageCHD(); CDImageCHD();
~CDImageCHD() override; ~CDImageCHD() override;
bool Open(const char* filename); bool Open(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -84,13 +85,16 @@ CDImageCHD::~CDImageCHD()
std::fclose(m_fp); std::fclose(m_fp);
} }
bool CDImageCHD::Open(const char* filename) bool CDImageCHD::Open(const char* filename, Common::Error* error)
{ {
Assert(!m_fp); Assert(!m_fp);
m_fp = FileSystem::OpenCFile(filename, "rb"); m_fp = FileSystem::OpenCFile(filename, "rb");
if (!m_fp) if (!m_fp)
{ {
Log_ErrorPrintf("Failed to open CHD '%s': errno %d", filename, errno); Log_ErrorPrintf("Failed to open CHD '%s': errno %d", filename, errno);
if (error)
error->SetErrno(errno);
return false; return false;
} }
@ -98,6 +102,9 @@ bool CDImageCHD::Open(const char* filename)
if (err != CHDERR_NONE) if (err != CHDERR_NONE)
{ {
Log_ErrorPrintf("Failed to open CHD '%s': %s", filename, chd_error_string(err)); Log_ErrorPrintf("Failed to open CHD '%s': %s", filename, chd_error_string(err));
if (error)
error->SetMessage(chd_error_string(err));
return false; return false;
} }
@ -106,6 +113,9 @@ bool CDImageCHD::Open(const char* filename)
if ((m_hunk_size % CHD_CD_SECTOR_DATA_SIZE) != 0) 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); 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; return false;
} }
@ -136,6 +146,9 @@ bool CDImageCHD::Open(const char* filename)
&pregap_frames, pgtype_str, pgsub_str, &postgap_frames) != 8) &pregap_frames, pgtype_str, pgsub_str, &postgap_frames) != 8)
{ {
Log_ErrorPrintf("Invalid track v2 metadata: '%s'", metadata_str); Log_ErrorPrintf("Invalid track v2 metadata: '%s'", metadata_str);
if (error)
error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str);
return false; 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) 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); Log_ErrorPrintf("Invalid track metadata: '%s'", metadata_str);
if (error)
error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str);
return false; 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), Log_ErrorPrintf("Incorrect track number at index %d, expected %d got %d", num_tracks, (num_tracks + 1),
track_num); 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; return false;
} }
@ -168,6 +190,9 @@ bool CDImageCHD::Open(const char* filename)
if (!mode.has_value()) if (!mode.has_value())
{ {
Log_ErrorPrintf("Invalid track mode: '%s'", type_str); Log_ErrorPrintf("Invalid track mode: '%s'", type_str);
if (error)
error->SetFormattedMessage("Invalid track mode: '%s'", type_str);
return false; return false;
} }
@ -198,6 +223,9 @@ bool CDImageCHD::Open(const char* filename)
if (pregap_frames > frames) if (pregap_frames > frames)
{ {
Log_ErrorPrintf("Pregap length %u exceeds track length %u", 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; return false;
} }
@ -242,6 +270,9 @@ bool CDImageCHD::Open(const char* filename)
if (m_tracks.empty()) if (m_tracks.empty())
{ {
Log_ErrorPrintf("File '%s' contains no tracks", filename); Log_ErrorPrintf("File '%s' contains no tracks", filename);
if (error)
error->SetFormattedMessage("File '%s' contains no tracks", filename);
return false; return false;
} }
@ -343,10 +374,10 @@ bool CDImageCHD::ReadHunk(u32 hunk_index)
return true; return true;
} }
std::unique_ptr<CDImage> CDImage::OpenCHDImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenCHDImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImageCHD> image = std::make_unique<CDImageCHD>(); std::unique_ptr<CDImageCHD> image = std::make_unique<CDImageCHD>();
if (!image->Open(filename)) if (!image->Open(filename, error))
return {}; return {};
return image; return image;

View file

@ -1,6 +1,7 @@
#include "assert.h" #include "assert.h"
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "log.h" #include "log.h"
#include <algorithm> #include <algorithm>
@ -15,7 +16,7 @@ public:
CDImageCueSheet(); CDImageCueSheet();
~CDImageCueSheet() override; ~CDImageCueSheet() override;
bool OpenAndParse(const char* filename); bool OpenAndParse(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -45,12 +46,15 @@ CDImageCueSheet::~CDImageCueSheet()
cd_delete(m_cd); cd_delete(m_cd);
} }
bool CDImageCueSheet::OpenAndParse(const char* filename) bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
{ {
std::optional<std::string> cuesheet_string = FileSystem::ReadFileToString(filename); std::optional<std::string> cuesheet_string = FileSystem::ReadFileToString(filename);
if (!cuesheet_string.has_value()) if (!cuesheet_string.has_value())
{ {
Log_ErrorPrintf("Failed to open cuesheet '%s': errno %d", filename, errno); Log_ErrorPrintf("Failed to open cuesheet '%s': errno %d", filename, errno);
if (error)
error->SetErrno(errno);
return false; return false;
} }
@ -62,6 +66,9 @@ bool CDImageCueSheet::OpenAndParse(const char* filename)
if (!m_cd) if (!m_cd)
{ {
Log_ErrorPrintf("Failed to parse cuesheet '%s'", filename); Log_ErrorPrintf("Failed to parse cuesheet '%s'", filename);
if (error)
error->SetMessage("Failed to parse cuesheet");
return false; return false;
} }
@ -80,6 +87,9 @@ bool CDImageCueSheet::OpenAndParse(const char* filename)
if (!track || !track_get_filename(track)) if (!track || !track_get_filename(track))
{ {
Log_ErrorPrintf("Track/filename missing for track %d", track_num); Log_ErrorPrintf("Track/filename missing for track %d", track_num);
if (error)
error->SetFormattedMessage("Track/filename missing for track %d", track_num);
return false; 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", 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); 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; return false;
} }
@ -142,8 +158,13 @@ bool CDImageCueSheet::OpenAndParse(const char* filename)
file_size /= track_sector_size; file_size /= track_sector_size;
if (track_start >= file_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, Log_ErrorPrintf("Failed to open track %u in '%s': track start is out of range (%ld vs %ld)", track_num,
track_start, file_size); 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; return false;
} }
@ -243,6 +264,8 @@ bool CDImageCueSheet::OpenAndParse(const char* filename)
if (m_tracks.empty()) if (m_tracks.empty())
{ {
Log_ErrorPrintf("File '%s' contains no tracks", filename); Log_ErrorPrintf("File '%s' contains no tracks", filename);
if (error)
error->SetFormattedMessage("File '%s' contains no tracks", filename);
return false; return false;
} }
@ -291,10 +314,10 @@ bool CDImageCueSheet::ReadSectorFromIndex(void* buffer, const Index& index, LBA
return true; return true;
} }
std::unique_ptr<CDImage> CDImage::OpenCueSheetImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenCueSheetImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImageCueSheet> image = std::make_unique<CDImageCueSheet>(); std::unique_ptr<CDImageCueSheet> image = std::make_unique<CDImageCueSheet>();
if (!image->OpenAndParse(filename)) if (!image->OpenAndParse(filename, error))
return {}; return {};
return image; return image;

View file

@ -1,6 +1,7 @@
#include "assert.h" #include "assert.h"
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "log.h" #include "log.h"
#include <array> #include <array>
@ -161,7 +162,7 @@ public:
CDImageEcm(); CDImageEcm();
~CDImageEcm() override; ~CDImageEcm() override;
bool Open(const char* filename); bool Open(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -221,13 +222,16 @@ CDImageEcm::~CDImageEcm()
std::fclose(m_fp); std::fclose(m_fp);
} }
bool CDImageEcm::Open(const char* filename) bool CDImageEcm::Open(const char* filename, Common::Error* error)
{ {
m_filename = filename; m_filename = filename;
m_fp = FileSystem::OpenCFile(filename, "rb"); m_fp = FileSystem::OpenCFile(filename, "rb");
if (!m_fp) if (!m_fp)
{ {
Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno); Log_ErrorPrintf("Failed to open binfile '%s': errno %d", filename, errno);
if (error)
error->SetErrno(errno);
return false; return false;
} }
@ -236,6 +240,9 @@ bool CDImageEcm::Open(const char* filename)
header[3] != 0) header[3] != 0)
{ {
Log_ErrorPrintf("Failed to read/invalid header"); Log_ErrorPrintf("Failed to read/invalid header");
if (error)
error->SetMessage("Failed to read/invalid header");
return false; return false;
} }
@ -250,6 +257,9 @@ bool CDImageEcm::Open(const char* filename)
if (bits == EOF) if (bits == EOF)
{ {
Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size()); 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; return false;
} }
@ -263,6 +273,9 @@ bool CDImageEcm::Open(const char* filename)
if (bits == EOF) if (bits == EOF)
{ {
Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size()); 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; return false;
} }
@ -280,6 +293,9 @@ bool CDImageEcm::Open(const char* filename)
if (count >= 0x80000000u) if (count >= 0x80000000u)
{ {
Log_ErrorPrintf("Corrupted header after %zu chunks", m_data_map.size()); 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; return false;
} }
@ -309,6 +325,9 @@ bool CDImageEcm::Open(const char* filename)
if (std::fseek(m_fp, file_offset, SEEK_SET) != 0) 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()); 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; return false;
} }
} }
@ -316,6 +335,9 @@ bool CDImageEcm::Open(const char* filename)
if (m_data_map.empty()) if (m_data_map.empty())
{ {
Log_ErrorPrintf("No data in image '%s'", filename); Log_ErrorPrintf("No data in image '%s'", filename);
if (error)
error->SetFormattedMessage("No data in image '%s'", filename);
return false; return false;
} }
@ -501,10 +523,10 @@ bool CDImageEcm::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
return true; return true;
} }
std::unique_ptr<CDImage> CDImage::OpenEcmImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenEcmImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImageEcm> image = std::make_unique<CDImageEcm>(); std::unique_ptr<CDImageEcm> image = std::make_unique<CDImageEcm>();
if (!image->Open(filename)) if (!image->Open(filename, error))
return {}; return {};
return image; return image;

View file

@ -1,6 +1,7 @@
#include "assert.h" #include "assert.h"
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "log.h" #include "log.h"
#include <algorithm> #include <algorithm>
@ -34,7 +35,7 @@ public:
CDImageMds(); CDImageMds();
~CDImageMds() override; ~CDImageMds() override;
bool OpenAndParse(const char* filename); bool OpenAndParse(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -56,12 +57,15 @@ CDImageMds::~CDImageMds()
std::fclose(m_mdf_file); 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"); std::FILE* mds_fp = FileSystem::OpenCFile(filename, "rb");
if (!mds_fp) if (!mds_fp)
{ {
Log_ErrorPrintf("Failed to open mds '%s': errno %d", filename, errno); Log_ErrorPrintf("Failed to open mds '%s': errno %d", filename, errno);
if (error)
error->SetErrno(errno);
return false; return false;
} }
@ -70,6 +74,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (!mds_data_opt.has_value() || mds_data_opt->size() < 0x54) if (!mds_data_opt.has_value() || mds_data_opt->size() < 0x54)
{ {
Log_ErrorPrintf("Failed to read mds file '%s'", filename); Log_ErrorPrintf("Failed to read mds file '%s'", filename);
if (error)
error->SetFormattedMessage("Failed to read mds file '%s'", filename);
return false; return false;
} }
@ -78,6 +85,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (!m_mdf_file) if (!m_mdf_file)
{ {
Log_ErrorPrintf("Failed to open mdf file '%s': errno %d", mdf_filename.c_str(), errno); 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; return false;
} }
@ -86,6 +96,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (std::memcmp(&mds[0], expected_signature, sizeof(expected_signature) - 1) != 0) if (std::memcmp(&mds[0], expected_signature, sizeof(expected_signature) - 1) != 0)
{ {
Log_ErrorPrintf("Incorrect signature in '%s'", filename); Log_ErrorPrintf("Incorrect signature in '%s'", filename);
if (error)
error->SetFormattedMessage("Incorrect signature in '%s'", filename);
return false; return false;
} }
@ -94,6 +107,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if ((session_offset + 24) > mds.size()) if ((session_offset + 24) > mds.size())
{ {
Log_ErrorPrintf("Invalid session offset in '%s'", filename); Log_ErrorPrintf("Invalid session offset in '%s'", filename);
if (error)
error->SetFormattedMessage("Invalid session offset in '%s'", filename);
return false; return false;
} }
@ -104,6 +120,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (track_count > 99 || track_offset >= mds.size()) if (track_count > 99 || track_offset >= mds.size())
{ {
Log_ErrorPrintf("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename); 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; return false;
} }
@ -122,6 +141,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if ((track_offset + sizeof(TrackEntry)) > mds.size()) if ((track_offset + sizeof(TrackEntry)) > mds.size())
{ {
Log_ErrorPrintf("End of file in '%s' at track %u", filename, track_number); 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; return false;
} }
@ -130,9 +152,12 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (PackedBCDToBinary(track.track_number) != track_number) if (PackedBCDToBinary(track.track_number) != track_number)
{ {
Log_ErrorPrintf("Unexpected track number 0x%02X in track %u", 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; return false;
} }
const bool contains_subchannel = (track.has_subchannel_data != 0); const bool contains_subchannel = (track.has_subchannel_data != 0);
const u32 track_sector_size = (contains_subchannel ? 2448 : RAW_SECTOR_SIZE); const u32 track_sector_size = (contains_subchannel ? 2448 : RAW_SECTOR_SIZE);
const TrackMode mode = (track.track_type == 0xA9) ? TrackMode::Audio : TrackMode::Mode2Raw; 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()) if ((track.extra_offset + sizeof(u32) + sizeof(u32)) > mds.size())
{ {
Log_ErrorPrintf("Invalid extra offset %u in track %u", track.extra_offset, track_number); 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; return false;
} }
@ -162,6 +190,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (track_pregap > track_start_lba) if (track_pregap > track_start_lba)
{ {
Log_ErrorPrintf("Track pregap %u is too large for start lba %u", 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; return false;
} }
@ -210,6 +241,9 @@ bool CDImageMds::OpenAndParse(const char* filename)
if (m_tracks.empty()) if (m_tracks.empty())
{ {
Log_ErrorPrintf("File '%s' contains no tracks", filename); Log_ErrorPrintf("File '%s' contains no tracks", filename);
if (error)
error->SetFormattedMessage("File '%s' contains no tracks", filename);
return false; return false;
} }
@ -257,10 +291,10 @@ bool CDImageMds::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
return true; return true;
} }
std::unique_ptr<CDImage> CDImage::OpenMdsImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenMdsImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImageMds> image = std::make_unique<CDImageMds>(); std::unique_ptr<CDImageMds> image = std::make_unique<CDImageMds>();
if (!image->OpenAndParse(filename)) if (!image->OpenAndParse(filename, error))
return {}; return {};
return image; return image;

View file

@ -1,5 +1,6 @@
#include "cd_image.h" #include "cd_image.h"
#include "cd_subchannel_replacement.h" #include "cd_subchannel_replacement.h"
#include "error.h"
#include "file_system.h" #include "file_system.h"
#include "log.h" #include "log.h"
#include "pbp_types.h" #include "pbp_types.h"
@ -18,7 +19,7 @@ public:
CDImagePBP() = default; CDImagePBP() = default;
~CDImagePBP() override; ~CDImagePBP() override;
bool Open(const char* filename); bool Open(const char* filename, Common::Error* error);
bool ReadSubChannelQ(SubChannelQ* subq) override; bool ReadSubChannelQ(SubChannelQ* subq) override;
bool HasNonStandardSubchannel() const override; bool HasNonStandardSubchannel() const override;
@ -45,7 +46,7 @@ private:
bool LoadSFOIndexTable(); bool LoadSFOIndexTable();
bool LoadSFOTable(); bool LoadSFOTable();
bool IsValidEboot(); bool IsValidEboot(Common::Error* error);
bool InitDecompressionStream(); bool InitDecompressionStream();
bool DecompressBlock(BlockInfo block_info); bool DecompressBlock(BlockInfo block_info);
@ -257,7 +258,7 @@ bool CDImagePBP::LoadSFOTable()
return true; return true;
} }
bool CDImagePBP::IsValidEboot() bool CDImagePBP::IsValidEboot(Common::Error* error)
{ {
// Check some fields to make sure this is a valid PS1 EBOOT.PBP // Check some fields to make sure this is a valid PS1 EBOOT.PBP
@ -268,12 +269,16 @@ bool CDImagePBP::IsValidEboot()
if (!std::holds_alternative<u32>(data_value) || std::get<u32>(data_value) != 1) if (!std::holds_alternative<u32>(data_value) || std::get<u32>(data_value) != 1)
{ {
Log_ErrorPrint("Invalid BOOTABLE value"); Log_ErrorPrint("Invalid BOOTABLE value");
if (error)
error->SetMessage("Invalid BOOTABLE value");
return false; return false;
} }
} }
else else
{ {
Log_ErrorPrint("No BOOTABLE value found"); Log_ErrorPrint("No BOOTABLE value found");
if (error)
error->SetMessage("No BOOTABLE value found");
return false; return false;
} }
@ -284,19 +289,23 @@ bool CDImagePBP::IsValidEboot()
if (!std::holds_alternative<std::string>(data_value) || std::get<std::string>(data_value) != "ME") if (!std::holds_alternative<std::string>(data_value) || std::get<std::string>(data_value) != "ME")
{ {
Log_ErrorPrint("Invalid CATEGORY value"); Log_ErrorPrint("Invalid CATEGORY value");
if (error)
error->SetMessage("Invalid CATEGORY value");
return false; return false;
} }
} }
else else
{ {
Log_ErrorPrint("No CATEGORY value found"); Log_ErrorPrint("No CATEGORY value found");
if (error)
error->SetMessage("No CATEGORY value found");
return false; return false;
} }
return true; return true;
} }
bool CDImagePBP::Open(const char* filename) bool CDImagePBP::Open(const char* filename, Common::Error* error)
{ {
if (!EndianHelper::HostIsLittleEndian()) if (!EndianHelper::HostIsLittleEndian())
{ {
@ -306,7 +315,12 @@ bool CDImagePBP::Open(const char* filename)
m_file = FileSystem::OpenCFile(filename, "rb"); m_file = FileSystem::OpenCFile(filename, "rb");
if (!m_file) if (!m_file)
{
if (error)
error->SetErrno(errno);
return false; return false;
}
m_filename = filename; m_filename = filename;
@ -314,6 +328,8 @@ bool CDImagePBP::Open(const char* filename)
if (!LoadPBPHeader()) if (!LoadPBPHeader())
{ {
Log_ErrorPrint("Failed to load PBP header"); Log_ErrorPrint("Failed to load PBP header");
if (error)
error->SetMessage("Failed to load PBP header");
return false; return false;
} }
@ -321,6 +337,8 @@ bool CDImagePBP::Open(const char* filename)
if (!LoadSFOHeader()) if (!LoadSFOHeader())
{ {
Log_ErrorPrint("Failed to load SFO header"); Log_ErrorPrint("Failed to load SFO header");
if (error)
error->SetMessage("Failed to load SFO header");
return false; return false;
} }
@ -328,6 +346,8 @@ bool CDImagePBP::Open(const char* filename)
if (!LoadSFOIndexTable()) if (!LoadSFOIndexTable())
{ {
Log_ErrorPrint("Failed to load SFO index table"); Log_ErrorPrint("Failed to load SFO index table");
if (error)
error->SetMessage("Failed to load SFO index table");
return false; return false;
} }
@ -335,11 +355,13 @@ bool CDImagePBP::Open(const char* filename)
if (!LoadSFOTable()) if (!LoadSFOTable())
{ {
Log_ErrorPrint("Failed to load SFO table"); Log_ErrorPrint("Failed to load SFO table");
if (error)
error->SetMessage("Failed to load SFO table");
return false; return false;
} }
// Since PBP files can store things that aren't PS1 CD images, make sure we're loading the right kind // 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"); Log_ErrorPrint("Couldn't validate EBOOT");
return false; return false;
@ -372,6 +394,9 @@ bool CDImagePBP::Open(const char* filename)
if (disc_table[0] == 0x44475000) // "\0PGD" if (disc_table[0] == 0x44475000) // "\0PGD"
{ {
Log_ErrorPrint("Encrypted PBP images are not supported"); Log_ErrorPrint("Encrypted PBP images are not supported");
if (error)
error->SetMessage("Encrypted PBP images are not supported");
return false; return false;
} }
@ -421,6 +446,9 @@ bool CDImagePBP::Open(const char* filename)
if (pgd_magic == 0x44475000) // "\0PGD" if (pgd_magic == 0x44475000) // "\0PGD"
{ {
Log_ErrorPrint("Encrypted PBP images are not supported"); Log_ErrorPrint("Encrypted PBP images are not supported");
if (error)
error->SetMessage("Encrypted PBP images are not supported");
return false; return false;
} }
@ -739,10 +767,10 @@ void CDImagePBP::PrintSFOTable(const SFOTable& sfo_table)
} }
#endif #endif
std::unique_ptr<CDImage> CDImage::OpenPBPImage(const char* filename) std::unique_ptr<CDImage> CDImage::OpenPBPImage(const char* filename, Common::Error* error)
{ {
std::unique_ptr<CDImagePBP> image = std::make_unique<CDImagePBP>(); std::unique_ptr<CDImagePBP> image = std::make_unique<CDImagePBP>();
if (!image->Open(filename)) if (!image->Open(filename, error))
return {}; return {};
return image; return image;

View file

@ -68,6 +68,7 @@
<ClInclude Include="d3d11\texture.h" /> <ClInclude Include="d3d11\texture.h" />
<ClInclude Include="dimensional_array.h" /> <ClInclude Include="dimensional_array.h" />
<ClInclude Include="easing.h" /> <ClInclude Include="easing.h" />
<ClInclude Include="error.h" />
<ClInclude Include="event.h" /> <ClInclude Include="event.h" />
<ClInclude Include="fifo_queue.h" /> <ClInclude Include="fifo_queue.h" />
<ClInclude Include="file_system.h" /> <ClInclude Include="file_system.h" />
@ -142,6 +143,7 @@
<ClCompile Include="d3d11\staging_texture.cpp" /> <ClCompile Include="d3d11\staging_texture.cpp" />
<ClCompile Include="d3d11\stream_buffer.cpp" /> <ClCompile Include="d3d11\stream_buffer.cpp" />
<ClCompile Include="d3d11\texture.cpp" /> <ClCompile Include="d3d11\texture.cpp" />
<ClCompile Include="error.cpp" />
<ClCompile Include="event.cpp" /> <ClCompile Include="event.cpp" />
<ClCompile Include="file_system.cpp" /> <ClCompile Include="file_system.cpp" />
<ClCompile Include="gl\context.cpp" /> <ClCompile Include="gl\context.cpp" />

View file

@ -111,6 +111,7 @@
<ClInclude Include="lru_cache.h" /> <ClInclude Include="lru_cache.h" />
<ClInclude Include="easing.h" /> <ClInclude Include="easing.h" />
<ClInclude Include="pbp_types.h" /> <ClInclude Include="pbp_types.h" />
<ClInclude Include="error.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="jit_code_buffer.cpp" /> <ClCompile Include="jit_code_buffer.cpp" />
@ -214,6 +215,7 @@
<ClCompile Include="cd_image_ecm.cpp" /> <ClCompile Include="cd_image_ecm.cpp" />
<ClCompile Include="cd_image_mds.cpp" /> <ClCompile Include="cd_image_mds.cpp" />
<ClCompile Include="cd_image_pbp.cpp" /> <ClCompile Include="cd_image_pbp.cpp" />
<ClCompile Include="error.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Natvis Include="bitfield.natvis" /> <Natvis Include="bitfield.natvis" />

View file

@ -4,6 +4,7 @@
#include "cdrom.h" #include "cdrom.h"
#include "cheats.h" #include "cheats.h"
#include "common/audio_stream.h" #include "common/audio_stream.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/iso_reader.h" #include "common/iso_reader.h"
#include "common/log.h" #include "common/log.h"
@ -66,7 +67,7 @@ static bool LoadEXE(const char* filename);
static bool SetExpansionROM(const char* filename); static bool SetExpansionROM(const char* filename);
/// Opens CD image, preloading if needed. /// Opens CD image, preloading if needed.
static std::unique_ptr<CDImage> OpenCDImage(const char* path, bool force_preload); static std::unique_ptr<CDImage> OpenCDImage(const char* path, Common::Error* error, bool force_preload);
static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display); static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display);
static bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, 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::string GetGameCodeForPath(const char* image_path, bool fallback_to_hash)
{ {
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path); std::unique_ptr<CDImage> cdi = CDImage::Open(image_path, nullptr);
if (!cdi) if (!cdi)
return {}; return {};
@ -656,7 +657,7 @@ std::optional<DiscRegion> GetRegionForPath(const char* image_path)
else if (IsPsfFileName(image_path)) else if (IsPsfFileName(image_path))
return GetRegionForPsf(image_path); return GetRegionForPsf(image_path);
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path); std::unique_ptr<CDImage> cdi = CDImage::Open(image_path, nullptr);
if (!cdi) if (!cdi)
return {}; return {};
@ -704,9 +705,9 @@ bool RecreateGPU(GPURenderer renderer, bool update_display /* = true*/)
return true; return true;
} }
std::unique_ptr<CDImage> OpenCDImage(const char* path, bool force_preload) std::unique_ptr<CDImage> OpenCDImage(const char* path, Common::Error* error, bool force_preload)
{ {
std::unique_ptr<CDImage> media = CDImage::Open(path); std::unique_ptr<CDImage> media = CDImage::Open(path, error);
if (!media) if (!media)
return {}; return {};
@ -796,12 +797,14 @@ bool Boot(const SystemBootParameters& params)
playlist_index = 0; playlist_index = 0;
} }
Common::Error error;
const std::string& media_path = s_media_playlist[playlist_index]; 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); 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) 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(); Shutdown();
return false; return false;
} }
@ -1215,22 +1218,24 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer, bool update_di
} }
else else
{ {
media = OpenCDImage(media_filename.c_str(), false); Common::Error error;
media = OpenCDImage(media_filename.c_str(), &error, false);
if (!media) if (!media)
{ {
if (old_media) if (old_media)
{ {
g_host_interface->AddFormattedOSDMessage( g_host_interface->AddFormattedOSDMessage(
30.0f, 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."), "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); media = std::move(old_media);
} }
else else
{ {
g_host_interface->ReportFormattedError( 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()); media_filename.c_str());
return false; return false;
} }
@ -1965,11 +1970,13 @@ std::string GetMediaFileName()
bool InsertMedia(const char* path) bool InsertMedia(const char* path)
{ {
std::unique_ptr<CDImage> image = OpenCDImage(path, false); Common::Error error;
std::unique_ptr<CDImage> image = OpenCDImage(path, &error, false);
if (!image) if (!image)
{ {
g_host_interface->AddFormattedOSDMessage( 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; return false;
} }

View file

@ -224,7 +224,7 @@ void GamePropertiesDialog::populateTracksInfo(const std::string& image_path)
m_ui.tracks->clearContents(); m_ui.tracks->clearContents();
m_path = image_path; m_path = image_path;
std::unique_ptr<CDImage> image = CDImage::Open(image_path.c_str()); std::unique_ptr<CDImage> image = CDImage::Open(image_path.c_str(), nullptr);
if (!image) if (!image)
return; return;
@ -860,7 +860,7 @@ void GamePropertiesDialog::computeTrackHashes()
if (m_path.empty()) if (m_path.empty())
return; return;
std::unique_ptr<CDImage> image = CDImage::Open(m_path.c_str()); std::unique_ptr<CDImage> image = CDImage::Open(m_path.c_str(), nullptr);
if (!image) if (!image)
return; return;

View file

@ -816,7 +816,7 @@ void GameChanged()
if (path.empty() || s_game_path == path) if (path.empty() || s_game_path == path)
return; return;
std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str()); std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str(), nullptr);
if (!cdi) if (!cdi)
{ {
Log_ErrorPrintf("Failed to open temporary CD image '%s'", path.c_str()); 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) if (playlist_index > 0 && playlist_index < playlist_count)
{ {
const std::string& first_disc_path(System::GetMediaPlaylistPath(0)); const std::string& first_disc_path(System::GetMediaPlaylistPath(0));
std::unique_ptr<CDImage> first_disc_image(CDImage::Open(first_disc_path.c_str())); std::unique_ptr<CDImage> first_disc_image(CDImage::Open(first_disc_path.c_str(), nullptr));
if (first_disc_image) if (first_disc_image)
{ {
Log_InfoPrintf("Using first disc '%s' from playlist (currently '%s')", first_disc_path.c_str(), path.c_str()); Log_InfoPrintf("Using first disc '%s' from playlist (currently '%s')", first_disc_path.c_str(), path.c_str());

View file

@ -168,7 +168,7 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
for (size_t i = 0; i < entries.size(); i++) for (size_t i = 0; i < entries.size(); i++)
{ {
std::unique_ptr<CDImage> entry_image = CDImage::Open(entries[i].c_str()); std::unique_ptr<CDImage> entry_image = CDImage::Open(entries[i].c_str(), nullptr);
if (!entry_image) if (!entry_image)
{ {
Log_ErrorPrintf("Failed to open entry %zu ('%s') in playlist %s", i, entries[i].c_str(), path); 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())) if (System::IsM3UFileName(path.c_str()))
return GetM3UListEntry(path.c_str(), entry); return GetM3UListEntry(path.c_str(), entry);
std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str()); std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str(), nullptr);
if (!cdi) if (!cdi)
return false; return false;