CDImage: Support loading subchannel from LSD files
This commit is contained in:
parent
7aa4180e17
commit
bc485ee55b
|
@ -99,7 +99,7 @@ bool CDImageBin::Open(const char* filename, Error* error)
|
||||||
|
|
||||||
AddLeadOutIndex();
|
AddLeadOutIndex();
|
||||||
|
|
||||||
m_sbi.LoadSBIFromImagePath(filename);
|
m_sbi.LoadFromImagePath(filename);
|
||||||
|
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,7 +413,7 @@ bool CDImageCHD::Open(const char* filename, Error* error)
|
||||||
m_lba_count = disc_lba;
|
m_lba_count = disc_lba;
|
||||||
AddLeadOutIndex();
|
AddLeadOutIndex();
|
||||||
|
|
||||||
m_sbi.LoadSBIFromImagePath(filename);
|
m_sbi.LoadFromImagePath(filename);
|
||||||
|
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Error* error)
|
||||||
m_lba_count = disc_lba;
|
m_lba_count = disc_lba;
|
||||||
AddLeadOutIndex();
|
AddLeadOutIndex();
|
||||||
|
|
||||||
m_sbi.LoadSBIFromImagePath(filename);
|
m_sbi.LoadFromImagePath(filename);
|
||||||
|
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,7 @@ bool CDImageEcm::Open(const char* filename, Error* error)
|
||||||
|
|
||||||
AddLeadOutIndex();
|
AddLeadOutIndex();
|
||||||
|
|
||||||
m_sbi.LoadSBIFromImagePath(filename);
|
m_sbi.LoadFromImagePath(filename);
|
||||||
|
|
||||||
m_chunk_buffer.reserve(RAW_SECTOR_SIZE * 2);
|
m_chunk_buffer.reserve(RAW_SECTOR_SIZE * 2);
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
|
|
|
@ -234,7 +234,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Error* error)
|
||||||
m_lba_count = m_tracks.back().start_lba + m_tracks.back().length;
|
m_lba_count = m_tracks.back().start_lba + m_tracks.back().length;
|
||||||
AddLeadOutIndex();
|
AddLeadOutIndex();
|
||||||
|
|
||||||
m_sbi.LoadSBIFromImagePath(filename);
|
m_sbi.LoadFromImagePath(filename);
|
||||||
|
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ bool CDImageMemory::CopyImage(CDImage* image, ProgressCallback* progress)
|
||||||
m_filename = image->GetFileName();
|
m_filename = image->GetFileName();
|
||||||
m_lba_count = image->GetLBACount();
|
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});
|
return Seek(1, Position{0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -668,12 +668,13 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
|
||||||
|
|
||||||
if (m_disc_offsets.size() > 1)
|
if (m_disc_offsets.size() > 1)
|
||||||
{
|
{
|
||||||
std::string sbi_path(Path::StripExtension(m_filename));
|
const std::string offset_path = fmt::format("{}_{}.pbp", Path::StripExtension(m_filename), index + 1);
|
||||||
sbi_path += TinyString::from_fmt("_%u.sbi", index + 1).view();
|
m_sbi.LoadFromImagePath(offset_path);
|
||||||
m_sbi.LoadSBI(sbi_path.c_str());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_sbi.LoadSBI(Path::ReplaceExtension(m_filename, "sbi").c_str());
|
{
|
||||||
|
m_sbi.LoadFromImagePath(Path::ReplaceExtension(m_filename, "sbi"));
|
||||||
|
}
|
||||||
|
|
||||||
m_current_disc = index;
|
m_current_disc = index;
|
||||||
return Seek(1, Position{0, 0, 0});
|
return Seek(1, Position{0, 0, 0});
|
||||||
|
|
|
@ -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)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "cd_subchannel_replacement.h"
|
#include "cd_subchannel_replacement.h"
|
||||||
|
@ -18,6 +18,14 @@ struct SBIFileEntry
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 data[10];
|
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)
|
#pragma pack(pop)
|
||||||
|
|
||||||
CDSubChannelReplacement::CDSubChannelReplacement() = default;
|
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);
|
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)
|
if (!fp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char header[4];
|
char header[4];
|
||||||
if (std::fread(header, sizeof(header), 1, fp.get()) != 1)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr char expected_header[] = {'S', 'B', 'I', '\0'};
|
static constexpr char expected_header[] = {'S', 'B', 'I', '\0'};
|
||||||
if (std::memcmp(header, expected_header, sizeof(header)) != 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,14 +67,14 @@ bool CDSubChannelReplacement::LoadSBI(const char* path)
|
||||||
if (!IsValidPackedBCD(entry.minute_bcd) || !IsValidPackedBCD(entry.second_bcd) ||
|
if (!IsValidPackedBCD(entry.minute_bcd) || !IsValidPackedBCD(entry.second_bcd) ||
|
||||||
!IsValidPackedBCD(entry.frame_bcd))
|
!IsValidPackedBCD(entry.frame_bcd))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Invalid position [%02x:%02x:%02x] in '%s'", entry.minute_bcd, entry.second_bcd, entry.frame_bcd,
|
Log_ErrorFmt("Invalid position [{:02x}:{:02x}:{:02x}] in '{}'", entry.minute_bcd, entry.second_bcd,
|
||||||
path);
|
entry.frame_bcd, path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.type != 1)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +91,50 @@ bool CDSubChannelReplacement::LoadSBI(const char* path)
|
||||||
m_replacement_subq.emplace(lba, subq);
|
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;
|
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)
|
void CDSubChannelReplacement::AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq)
|
||||||
|
|
|
@ -16,8 +16,7 @@ public:
|
||||||
|
|
||||||
u32 GetReplacementSectorCount() const { return static_cast<u32>(m_replacement_subq.size()); }
|
u32 GetReplacementSectorCount() const { return static_cast<u32>(m_replacement_subq.size()); }
|
||||||
|
|
||||||
bool LoadSBI(const char* path);
|
bool LoadFromImagePath(std::string_view image_path);
|
||||||
bool LoadSBIFromImagePath(const char* image_path);
|
|
||||||
|
|
||||||
/// Adds a sector to the replacement map.
|
/// Adds a sector to the replacement map.
|
||||||
void AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq);
|
void AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq);
|
||||||
|
@ -31,5 +30,8 @@ public:
|
||||||
private:
|
private:
|
||||||
using ReplacementMap = std::unordered_map<u32, CDImage::SubChannelQ>;
|
using ReplacementMap = std::unordered_map<u32, CDImage::SubChannelQ>;
|
||||||
|
|
||||||
|
bool LoadSBI(const std::string& path);
|
||||||
|
bool LoadLSD(const std::string& path);
|
||||||
|
|
||||||
ReplacementMap m_replacement_subq;
|
ReplacementMap m_replacement_subq;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue