CDImage: Support loading subchannel from LSD files

This commit is contained in:
Stenzek 2023-11-15 19:05:21 +10:00
parent 7aa4180e17
commit bc485ee55b
No known key found for this signature in database
9 changed files with 71 additions and 23 deletions

View file

@ -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});
}

View file

@ -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});
}

View file

@ -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});
}

View file

@ -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});

View file

@ -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});
}

View file

@ -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});
}

View file

@ -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});

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// 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::LoadSBIFromImagePath(const char* image_path)
bool CDSubChannelReplacement::LoadLSD(const std::string& path)
{
return LoadSBI(Path::ReplaceExtension(image_path, "sbi").c_str());
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::LoadFromImagePath(std::string_view image_path)
{
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)

View file

@ -16,8 +16,7 @@ public:
u32 GetReplacementSectorCount() const { return static_cast<u32>(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 @@ public:
private:
using ReplacementMap = std::unordered_map<u32, CDImage::SubChannelQ>;
bool LoadSBI(const std::string& path);
bool LoadLSD(const std::string& path);
ReplacementMap m_replacement_subq;
};