diff --git a/src/core/game_database.cpp b/src/core/game_database.cpp index ca0de65936..9e78200dfd 100644 --- a/src/core/game_database.cpp +++ b/src/core/game_database.cpp @@ -129,7 +129,7 @@ std::string GameDatabase::GetSerialForPath(const char* path) if (System::IsLoadableFilename(path) && !System::IsExeFileName(path) && !System::IsPsfFileName(path)) { - std::unique_ptr image(CDImage::Open(path, nullptr)); + std::unique_ptr image(CDImage::Open(path, false, nullptr)); if (image) ret = GetSerialForDisc(image.get()); } diff --git a/src/core/settings.cpp b/src/core/settings.cpp index ecaaf8cec2..3db665e43f 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -269,6 +269,7 @@ void Settings::Load(SettingsInterface& si) static_cast(si.GetIntValue("CDROM", "ReadaheadSectors", DEFAULT_CDROM_READAHEAD_SECTORS)); cdrom_region_check = si.GetBoolValue("CDROM", "RegionCheck", false); cdrom_load_image_to_ram = si.GetBoolValue("CDROM", "LoadImageToRAM", false); + cdrom_load_image_patches = si.GetBoolValue("CDROM", "LoadImagePatches", false); cdrom_mute_cd_audio = si.GetBoolValue("CDROM", "MuteCDAudio", false); cdrom_read_speedup = si.GetIntValue("CDROM", "ReadSpeedup", 1); cdrom_seek_speedup = si.GetIntValue("CDROM", "SeekSpeedup", 1); @@ -474,6 +475,7 @@ void Settings::Save(SettingsInterface& si) const si.SetIntValue("CDROM", "ReadaheadSectors", cdrom_readahead_sectors); si.SetBoolValue("CDROM", "RegionCheck", cdrom_region_check); si.SetBoolValue("CDROM", "LoadImageToRAM", cdrom_load_image_to_ram); + si.SetBoolValue("CDROM", "LoadImagePatches", cdrom_load_image_patches); si.SetBoolValue("CDROM", "MuteCDAudio", cdrom_mute_cd_audio); si.SetIntValue("CDROM", "ReadSpeedup", cdrom_read_speedup); si.SetIntValue("CDROM", "SeekSpeedup", cdrom_seek_speedup); diff --git a/src/core/settings.h b/src/core/settings.h index 039aa793ec..7bdcf13904 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -143,6 +143,7 @@ struct Settings u8 cdrom_readahead_sectors = DEFAULT_CDROM_READAHEAD_SECTORS; bool cdrom_region_check = false; bool cdrom_load_image_to_ram = false; + bool cdrom_load_image_patches = false; bool cdrom_mute_cd_audio = false; u32 cdrom_read_speedup = 1; u32 cdrom_seek_speedup = 1; diff --git a/src/core/system.cpp b/src/core/system.cpp index 997e25af46..118eae6050 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -87,11 +87,8 @@ static bool LoadEXE(const char* filename); static std::string GetExecutableNameForImage(ISOReader& iso, bool strip_subdirectories); -/// Opens CD image, preloading if needed. -static std::unique_ptr OpenCDImage(const char* path, Common::Error* error, bool check_for_patches); static bool ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name, std::vector* out_executable_data); -static bool ShouldCheckForImagePatches(); static void StallCPU(TickCount ticks); @@ -406,7 +403,7 @@ ConsoleRegion System::GetConsoleRegionForDiscRegion(DiscRegion region) std::string System::GetGameCodeForPath(const char* image_path, bool fallback_to_hash) { - std::unique_ptr cdi = CDImage::Open(image_path, nullptr); + std::unique_ptr cdi = CDImage::Open(image_path, false, nullptr); if (!cdi) return {}; @@ -694,7 +691,7 @@ std::optional System::GetRegionForPath(const char* image_path) else if (IsPsfFileName(image_path)) return GetRegionForPsf(image_path); - std::unique_ptr cdi = CDImage::Open(image_path, nullptr); + std::unique_ptr cdi = CDImage::Open(image_path, false, nullptr); if (!cdi) return {}; @@ -753,37 +750,6 @@ bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_display, bool return true; } -std::unique_ptr System::OpenCDImage(const char* path, Common::Error* error, bool check_for_patches) -{ - std::unique_ptr media = CDImage::Open(path, error); - if (!media) - return {}; - - if (check_for_patches) - { - const std::string ppf_filename( - Path::BuildRelativePath(path, Path::ReplaceExtension(FileSystem::GetDisplayNameFromPath(path), "ppf"))); - if (FileSystem::FileExists(ppf_filename.c_str())) - { - media = CDImage::OverlayPPFPatch(ppf_filename.c_str(), std::move(media)); - if (!media) - { - Host::AddFormattedOSDMessage( - 30.0f, Host::TranslateString("OSDMessage", "Failed to apply ppf patch from '%s', using unpatched image."), - ppf_filename.c_str()); - return OpenCDImage(path, error, false); - } - } - } - - return media; -} - -bool System::ShouldCheckForImagePatches() -{ - return Host::GetBoolSettingValue("CDROM", "LoadImagePatches", false); -} - void System::LoadSettings(bool display_osd_messages) { std::unique_lock lock = Host::GetSettingsLock(); @@ -1094,7 +1060,7 @@ bool System::BootSystem(SystemBootParameters parameters) else { Log_InfoPrintf("Loading CD image '%s'...", parameters.filename.c_str()); - media = OpenCDImage(parameters.filename.c_str(), &error, ShouldCheckForImagePatches()); + media = CDImage::Open(parameters.filename.c_str(), g_settings.cdrom_load_image_patches, &error); if (!media) { Host::ReportErrorAsync("Error", fmt::format("Failed to load CD image '{}': {}", @@ -1777,7 +1743,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u } else { - media = OpenCDImage(media_filename.c_str(), &error, ShouldCheckForImagePatches()); + media = CDImage::Open(media_filename.c_str(), g_settings.cdrom_load_image_patches, &error); if (!media) { if (old_media) @@ -2831,7 +2797,7 @@ std::string System::GetMediaFileName() bool System::InsertMedia(const char* path) { Common::Error error; - std::unique_ptr image = OpenCDImage(path, &error, ShouldCheckForImagePatches()); + std::unique_ptr image = CDImage::Open(path, g_settings.cdrom_load_image_patches, &error); if (!image) { Host::AddFormattedOSDMessage(10.0f, Host::TranslateString("OSDMessage", "Failed to open disc image '%s': %s."), diff --git a/src/duckstation-qt/gamesummarywidget.cpp b/src/duckstation-qt/gamesummarywidget.cpp index e28406d871..a9d28222d0 100644 --- a/src/duckstation-qt/gamesummarywidget.cpp +++ b/src/duckstation-qt/gamesummarywidget.cpp @@ -161,7 +161,7 @@ void GameSummaryWidget::populateTracksInfo() m_ui.tracks->clearContents(); QtUtils::ResizeColumnsForTableView(m_ui.tracks, {70, 75, 95, 95, 215, 40}); - std::unique_ptr image = CDImage::Open(m_path.c_str(), nullptr); + std::unique_ptr image = CDImage::Open(m_path.c_str(), false, nullptr); if (!image) return; @@ -206,7 +206,7 @@ void GameSummaryWidget::onComputeHashClicked() return; } - std::unique_ptr image = CDImage::Open(m_path.c_str(), nullptr); + std::unique_ptr image = CDImage::Open(m_path.c_str(), false, nullptr); if (!image) { QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), tr("Failed to open CD image for hashing.")); diff --git a/src/frontend-common/achievements.cpp b/src/frontend-common/achievements.cpp index c888aa3238..622341f459 100644 --- a/src/frontend-common/achievements.cpp +++ b/src/frontend-common/achievements.cpp @@ -1307,7 +1307,7 @@ void Achievements::GameChanged(const std::string& path, CDImage* image) if (!path.empty() && (!image || (g_settings.achievements_use_first_disc_from_playlist && image->HasSubImages() && image->GetCurrentSubImage() != 0))) { - temp_image = CDImage::Open(path.c_str(), nullptr); + temp_image = CDImage::Open(path.c_str(), g_settings.cdrom_load_image_patches, nullptr); image = temp_image.get(); if (!temp_image) { @@ -1336,7 +1336,8 @@ void Achievements::GameChanged(const std::string& path, CDImage* image) if (image && image->HasSubImages() && image->GetCurrentSubImage() != 0) { - std::unique_ptr image_copy(CDImage::Open(image->GetFileName().c_str(), nullptr)); + std::unique_ptr image_copy( + CDImage::Open(image->GetFileName().c_str(), g_settings.cdrom_load_image_patches, nullptr)); if (!image_copy) { Log_ErrorPrintf("Failed to reopen image '%s'", image->GetFileName().c_str()); diff --git a/src/frontend-common/game_list.cpp b/src/frontend-common/game_list.cpp index 6eb35185eb..eaec4a1a1a 100644 --- a/src/frontend-common/game_list.cpp +++ b/src/frontend-common/game_list.cpp @@ -164,7 +164,7 @@ bool GameList::GetPsfListEntry(const std::string& path, Entry* entry) bool GameList::GetDiscListEntry(const std::string& path, Entry* entry) { - std::unique_ptr cdi = CDImage::Open(path.c_str(), nullptr); + std::unique_ptr cdi = CDImage::Open(path.c_str(), false, nullptr); if (!cdi) return false; diff --git a/src/util/cd_image.cpp b/src/util/cd_image.cpp index cfa8c2b2cc..fb95010598 100644 --- a/src/util/cd_image.cpp +++ b/src/util/cd_image.cpp @@ -1,5 +1,6 @@ #include "cd_image.h" #include "common/assert.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.h" #include "common/path.h" @@ -17,7 +18,7 @@ u32 CDImage::GetBytesPerSector(TrackMode mode) return sizes[static_cast(mode)]; } -std::unique_ptr CDImage::Open(const char* filename, Common::Error* error) +std::unique_ptr CDImage::Open(const char* filename, bool allow_patches, Common::Error* error) { const char* extension; @@ -37,43 +38,67 @@ std::unique_ptr CDImage::Open(const char* filename, Common::Error* erro return nullptr; } + std::unique_ptr image; if (StringUtil::Strcasecmp(extension, ".cue") == 0) { - return OpenCueSheetImage(filename, error); + image = OpenCueSheetImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".bin") == 0 || StringUtil::Strcasecmp(extension, ".img") == 0 || StringUtil::Strcasecmp(extension, ".iso") == 0) { - return OpenBinImage(filename, error); + image = OpenBinImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".chd") == 0) { - return OpenCHDImage(filename, error); + image = OpenCHDImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".ecm") == 0) { - return OpenEcmImage(filename, error); + image = OpenEcmImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".mds") == 0) { - return OpenMdsImage(filename, error); + image = OpenMdsImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".pbp") == 0) { - return OpenPBPImage(filename, error); + image = OpenPBPImage(filename, error); } else if (StringUtil::Strcasecmp(extension, ".m3u") == 0) { - return OpenM3uImage(filename, error); + image = OpenM3uImage(filename, allow_patches, error); + } + else if (IsDeviceName(filename)) + { + image = OpenDeviceImage(filename, error); + } + else + { + Log_ErrorPrintf("Unknown extension '%s' from filename '%s'", extension, filename); + return nullptr; } - if (IsDeviceName(filename)) - return OpenDeviceImage(filename, error); - -#undef CASE_COMPARE + if (allow_patches) + { +#ifdef __ANDROID__ + const std::string ppf_filename( + Path::BuildRelativePath(filename, Path::ReplaceExtension(filename_display_name, "ppf"))); +#else + const std::string ppf_filename( + Path::BuildRelativePath(filename, Path::ReplaceExtension(Path::GetFileName(filename), "ppf"))); +#endif + if (FileSystem::FileExists(ppf_filename.c_str())) + { + image = CDImage::OverlayPPFPatch(ppf_filename.c_str(), std::move(image)); + if (!image) + { + if (error) + error->SetFormattedMessage("Failed to apply ppf patch from '%s'.", ppf_filename.c_str()); + } + } + } - Log_ErrorPrintf("Unknown extension '%s' from filename '%s'", extension, filename); - return nullptr; + return image; } CDImage::LBA CDImage::GetTrackStartPosition(u8 track) const diff --git a/src/util/cd_image.h b/src/util/cd_image.h index 653845ae8d..1fbb37f2d3 100644 --- a/src/util/cd_image.h +++ b/src/util/cd_image.h @@ -217,14 +217,14 @@ class CDImage static bool IsDeviceName(const char* filename); // Opening disc image. - static std::unique_ptr Open(const char* filename, Common::Error* error); + static std::unique_ptr Open(const char* filename, bool allow_patches, 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 OpenM3uImage(const char* filename, Common::Error* error); + static std::unique_ptr OpenM3uImage(const char* filename, bool apply_patches, Common::Error* error); static std::unique_ptr OpenDeviceImage(const char* filename, Common::Error* error); static std::unique_ptr CreateMemoryImage(CDImage* image, ProgressCallback* progress = ProgressCallback::NullProgressCallback); @@ -232,15 +232,42 @@ class CDImage ProgressCallback* progress = ProgressCallback::NullProgressCallback); // Accessors. - const std::string& GetFileName() const { return m_filename; } - LBA GetPositionOnDisc() const { return m_position_on_disc; } - Position GetMSFPositionOnDisc() const { return Position::FromLBA(m_position_on_disc); } - LBA GetPositionInTrack() const { return m_position_in_track; } - Position GetMSFPositionInTrack() const { return Position::FromLBA(m_position_in_track); } - LBA GetLBACount() const { return m_lba_count; } - u32 GetIndexNumber() const { return m_current_index->index_number; } - u32 GetTrackNumber() const { return m_current_index->track_number; } - u32 GetTrackCount() const { return static_cast(m_tracks.size()); } + const std::string& GetFileName() const + { + return m_filename; + } + LBA GetPositionOnDisc() const + { + return m_position_on_disc; + } + Position GetMSFPositionOnDisc() const + { + return Position::FromLBA(m_position_on_disc); + } + LBA GetPositionInTrack() const + { + return m_position_in_track; + } + Position GetMSFPositionInTrack() const + { + return Position::FromLBA(m_position_in_track); + } + LBA GetLBACount() const + { + return m_lba_count; + } + u32 GetIndexNumber() const + { + return m_current_index->index_number; + } + u32 GetTrackNumber() const + { + return m_current_index->track_number; + } + u32 GetTrackCount() const + { + return static_cast(m_tracks.size()); + } LBA GetTrackStartPosition(u8 track) const; Position GetTrackStartMSFPosition(u8 track) const; LBA GetTrackLength(u8 track) const; @@ -248,11 +275,26 @@ class CDImage TrackMode GetTrackMode(u8 track) const; LBA GetTrackIndexPosition(u8 track, u8 index) const; LBA GetTrackIndexLength(u8 track, u8 index) const; - u32 GetFirstTrackNumber() const { return m_tracks.front().track_number; } - u32 GetLastTrackNumber() const { return m_tracks.back().track_number; } - u32 GetIndexCount() const { return static_cast(m_indices.size()); } - const std::vector& GetTracks() const { return m_tracks; } - const std::vector& GetIndices() const { return m_indices; } + u32 GetFirstTrackNumber() const + { + return m_tracks.front().track_number; + } + u32 GetLastTrackNumber() const + { + return m_tracks.back().track_number; + } + u32 GetIndexCount() const + { + return static_cast(m_indices.size()); + } + const std::vector& GetTracks() const + { + return m_tracks; + } + const std::vector& GetIndices() const + { + return m_indices; + } const Track& GetTrack(u32 track) const; const Index& GetIndex(u32 i) const; diff --git a/src/util/cd_image_m3u.cpp b/src/util/cd_image_m3u.cpp index ccdcec34c6..4d6d419fdd 100644 --- a/src/util/cd_image_m3u.cpp +++ b/src/util/cd_image_m3u.cpp @@ -17,7 +17,7 @@ class CDImageM3u : public CDImage CDImageM3u(); ~CDImageM3u() override; - bool Open(const char* path, Common::Error* Error); + bool Open(const char* path, bool apply_patches, Common::Error* Error); bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override; bool HasNonStandardSubchannel() const override; @@ -42,13 +42,14 @@ class CDImageM3u : public CDImage std::vector m_entries; std::unique_ptr m_current_image; u32 m_current_image_index = UINT32_C(0xFFFFFFFF); + bool m_apply_patches = false; }; CDImageM3u::CDImageM3u() = default; CDImageM3u::~CDImageM3u() = default; -bool CDImageM3u::Open(const char* path, Common::Error* error) +bool CDImageM3u::Open(const char* path, bool apply_patches, Common::Error* error) { std::FILE* fp = FileSystem::OpenCFile(path, "rb"); if (!fp) @@ -65,6 +66,7 @@ bool CDImageM3u::Open(const char* path, Common::Error* error) std::istringstream ifs(m3u_file.value()); m_filename = path; + m_apply_patches = apply_patches; std::vector entries; std::string line; @@ -131,7 +133,7 @@ bool CDImageM3u::SwitchSubImage(u32 index, Common::Error* error) return true; const Entry& entry = m_entries[index]; - std::unique_ptr new_image = CDImage::Open(entry.filename.c_str(), error); + std::unique_ptr new_image = CDImage::Open(entry.filename.c_str(), m_apply_patches, error); if (!new_image) { Log_ErrorPrintf("Failed to load subimage %u (%s)", index, entry.filename.c_str()); @@ -170,10 +172,10 @@ bool CDImageM3u::ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_ return m_current_image->ReadSubChannelQ(subq, index, lba_in_index); } -std::unique_ptr CDImage::OpenM3uImage(const char* filename, Common::Error* error) +std::unique_ptr CDImage::OpenM3uImage(const char* filename, bool apply_patches, Common::Error* error) { std::unique_ptr image = std::make_unique(); - if (!image->Open(filename, error)) + if (!image->Open(filename, apply_patches, error)) return {}; return image;