From bc485ee55b75f031b160d4687c644c2374328012 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 15 Nov 2023 19:05:21 +1000 Subject: [PATCH] CDImage: Support loading subchannel from LSD files --- src/util/cd_image_bin.cpp | 2 +- src/util/cd_image_chd.cpp | 2 +- src/util/cd_image_cue.cpp | 2 +- src/util/cd_image_ecm.cpp | 2 +- src/util/cd_image_mds.cpp | 2 +- src/util/cd_image_memory.cpp | 2 +- src/util/cd_image_pbp.cpp | 9 ++-- src/util/cd_subchannel_replacement.cpp | 67 +++++++++++++++++++++----- src/util/cd_subchannel_replacement.h | 6 ++- 9 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/util/cd_image_bin.cpp b/src/util/cd_image_bin.cpp index 1b181a6358..dcc980e55c 100644 --- a/src/util/cd_image_bin.cpp +++ b/src/util/cd_image_bin.cpp @@ -99,7 +99,7 @@ bool CDImageBin::Open(const char* filename, Error* error) AddLeadOutIndex(); - m_sbi.LoadSBIFromImagePath(filename); + m_sbi.LoadFromImagePath(filename); return Seek(1, Position{0, 0, 0}); } diff --git a/src/util/cd_image_chd.cpp b/src/util/cd_image_chd.cpp index e08194ed65..8b8cb627a5 100644 --- a/src/util/cd_image_chd.cpp +++ b/src/util/cd_image_chd.cpp @@ -413,7 +413,7 @@ bool CDImageCHD::Open(const char* filename, Error* error) m_lba_count = disc_lba; AddLeadOutIndex(); - m_sbi.LoadSBIFromImagePath(filename); + m_sbi.LoadFromImagePath(filename); return Seek(1, Position{0, 0, 0}); } diff --git a/src/util/cd_image_cue.cpp b/src/util/cd_image_cue.cpp index 0a70d9e93b..1b434a8346 100644 --- a/src/util/cd_image_cue.cpp +++ b/src/util/cd_image_cue.cpp @@ -293,7 +293,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Error* error) m_lba_count = disc_lba; AddLeadOutIndex(); - m_sbi.LoadSBIFromImagePath(filename); + m_sbi.LoadFromImagePath(filename); return Seek(1, Position{0, 0, 0}); } diff --git a/src/util/cd_image_ecm.cpp b/src/util/cd_image_ecm.cpp index f828d85863..5698b833c6 100644 --- a/src/util/cd_image_ecm.cpp +++ b/src/util/cd_image_ecm.cpp @@ -400,7 +400,7 @@ bool CDImageEcm::Open(const char* filename, Error* error) AddLeadOutIndex(); - m_sbi.LoadSBIFromImagePath(filename); + m_sbi.LoadFromImagePath(filename); m_chunk_buffer.reserve(RAW_SECTOR_SIZE * 2); return Seek(1, Position{0, 0, 0}); diff --git a/src/util/cd_image_mds.cpp b/src/util/cd_image_mds.cpp index 1622f36b85..b6d6c1b547 100644 --- a/src/util/cd_image_mds.cpp +++ b/src/util/cd_image_mds.cpp @@ -234,7 +234,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Error* error) m_lba_count = m_tracks.back().start_lba + m_tracks.back().length; AddLeadOutIndex(); - m_sbi.LoadSBIFromImagePath(filename); + m_sbi.LoadFromImagePath(filename); return Seek(1, Position{0, 0, 0}); } diff --git a/src/util/cd_image_memory.cpp b/src/util/cd_image_memory.cpp index a448affc24..8ccf1db492 100644 --- a/src/util/cd_image_memory.cpp +++ b/src/util/cd_image_memory.cpp @@ -115,7 +115,7 @@ bool CDImageMemory::CopyImage(CDImage* image, ProgressCallback* progress) m_filename = image->GetFileName(); m_lba_count = image->GetLBACount(); - m_sbi.LoadSBI(Path::ReplaceExtension(m_filename, "sbi").c_str()); + m_sbi.LoadFromImagePath(m_filename); return Seek(1, Position{0, 0, 0}); } diff --git a/src/util/cd_image_pbp.cpp b/src/util/cd_image_pbp.cpp index 3e5b9e4743..eabad36277 100644 --- a/src/util/cd_image_pbp.cpp +++ b/src/util/cd_image_pbp.cpp @@ -668,12 +668,13 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error) if (m_disc_offsets.size() > 1) { - std::string sbi_path(Path::StripExtension(m_filename)); - sbi_path += TinyString::from_fmt("_%u.sbi", index + 1).view(); - m_sbi.LoadSBI(sbi_path.c_str()); + const std::string offset_path = fmt::format("{}_{}.pbp", Path::StripExtension(m_filename), index + 1); + m_sbi.LoadFromImagePath(offset_path); } else - m_sbi.LoadSBI(Path::ReplaceExtension(m_filename, "sbi").c_str()); + { + m_sbi.LoadFromImagePath(Path::ReplaceExtension(m_filename, "sbi")); + } m_current_disc = index; return Seek(1, Position{0, 0, 0}); diff --git a/src/util/cd_subchannel_replacement.cpp b/src/util/cd_subchannel_replacement.cpp index 2507ec36ee..f8ae0113b6 100644 --- a/src/util/cd_subchannel_replacement.cpp +++ b/src/util/cd_subchannel_replacement.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "cd_subchannel_replacement.h" @@ -18,6 +18,14 @@ struct SBIFileEntry u8 type; u8 data[10]; }; +struct LSDFileEntry +{ + u8 minute_bcd; + u8 second_bcd; + u8 frame_bcd; + u8 data[12]; +}; +static_assert(sizeof(LSDFileEntry) == 15); #pragma pack(pop) CDSubChannelReplacement::CDSubChannelReplacement() = default; @@ -33,23 +41,23 @@ static constexpr u32 MSFToLBA(u8 minute_bcd, u8 second_bcd, u8 frame_bcd) return (ZeroExtend32(minute) * 60 * 75) + (ZeroExtend32(second) * 75) + ZeroExtend32(frame); } -bool CDSubChannelReplacement::LoadSBI(const char* path) +bool CDSubChannelReplacement::LoadSBI(const std::string& path) { - auto fp = FileSystem::OpenManagedCFile(path, "rb"); + auto fp = FileSystem::OpenManagedCFile(path.c_str(), "rb"); if (!fp) return false; char header[4]; if (std::fread(header, sizeof(header), 1, fp.get()) != 1) { - Log_ErrorPrintf("Failed to read header for '%s'", path); + Log_ErrorFmt("Failed to read header for '{}'", path); return true; } static constexpr char expected_header[] = {'S', 'B', 'I', '\0'}; if (std::memcmp(header, expected_header, sizeof(header)) != 0) { - Log_ErrorPrintf("Invalid header in '%s'", path); + Log_ErrorFmt("Invalid header in '{}'", path); return true; } @@ -59,14 +67,14 @@ bool CDSubChannelReplacement::LoadSBI(const char* path) if (!IsValidPackedBCD(entry.minute_bcd) || !IsValidPackedBCD(entry.second_bcd) || !IsValidPackedBCD(entry.frame_bcd)) { - Log_ErrorPrintf("Invalid position [%02x:%02x:%02x] in '%s'", entry.minute_bcd, entry.second_bcd, entry.frame_bcd, - path); + Log_ErrorFmt("Invalid position [{:02x}:{:02x}:{:02x}] in '{}'", entry.minute_bcd, entry.second_bcd, + entry.frame_bcd, path); return false; } if (entry.type != 1) { - Log_ErrorPrintf("Invalid type 0x%02X in '%s'", entry.type, path); + Log_ErrorFmt("Invalid type 0x{:02X} in '{}'", entry.type, path); return false; } @@ -83,13 +91,50 @@ bool CDSubChannelReplacement::LoadSBI(const char* path) m_replacement_subq.emplace(lba, subq); } - Log_InfoPrintf("Loaded %zu replacement sectors from '%s'", m_replacement_subq.size(), path); + Log_InfoFmt("Loaded {} replacement sectors from SBI '{}'", m_replacement_subq.size(), path); + return true; +} + +bool CDSubChannelReplacement::LoadLSD(const std::string& path) +{ + auto fp = FileSystem::OpenManagedCFile(path.c_str(), "rb"); + if (!fp) + return false; + + LSDFileEntry entry; + while (std::fread(&entry, sizeof(entry), 1, fp.get()) == 1) + { + if (!IsValidPackedBCD(entry.minute_bcd) || !IsValidPackedBCD(entry.second_bcd) || + !IsValidPackedBCD(entry.frame_bcd)) + { + Log_ErrorFmt("Invalid position [{:02x}:{:02x}:{:02x}] in '{}'", entry.minute_bcd, entry.second_bcd, + entry.frame_bcd, path); + return false; + } + + const u32 lba = MSFToLBA(entry.minute_bcd, entry.second_bcd, entry.frame_bcd); + + CDImage::SubChannelQ subq; + std::copy_n(entry.data, countof(entry.data), subq.data.data()); + + Log_DebugFmt("{:02x}:{:02x}:{:02x}: CRC {}", entry.minute_bcd, entry.second_bcd, entry.frame_bcd, + subq.IsCRCValid() ? "VALID" : "INVALID"); + m_replacement_subq.emplace(lba, subq); + } + + Log_InfoFmt("Loaded {} replacement sectors from LSD '{}'", m_replacement_subq.size(), path); return true; } -bool CDSubChannelReplacement::LoadSBIFromImagePath(const char* image_path) +bool CDSubChannelReplacement::LoadFromImagePath(std::string_view image_path) { - return LoadSBI(Path::ReplaceExtension(image_path, "sbi").c_str()); + if (const std::string filename = Path::ReplaceExtension(image_path, "sbi"); LoadSBI(filename.c_str())) + return true; + + if (const std::string filename = Path::ReplaceExtension(image_path, "lsd"); LoadLSD(filename.c_str())) + return true; + + return false; } void CDSubChannelReplacement::AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq) diff --git a/src/util/cd_subchannel_replacement.h b/src/util/cd_subchannel_replacement.h index 92545cfe13..a0111fe7a1 100644 --- a/src/util/cd_subchannel_replacement.h +++ b/src/util/cd_subchannel_replacement.h @@ -16,8 +16,7 @@ class CDSubChannelReplacement u32 GetReplacementSectorCount() const { return static_cast(m_replacement_subq.size()); } - bool LoadSBI(const char* path); - bool LoadSBIFromImagePath(const char* image_path); + bool LoadFromImagePath(std::string_view image_path); /// Adds a sector to the replacement map. void AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq); @@ -31,5 +30,8 @@ class CDSubChannelReplacement private: using ReplacementMap = std::unordered_map; + bool LoadSBI(const std::string& path); + bool LoadLSD(const std::string& path); + ReplacementMap m_replacement_subq; };