mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 10:38:46 -04:00
68667cd58b
Two path-resolution defects where the runtime silently accepted only one of
two equally-valid spellings of the same input.
1. Disc: picking the .cue threw away the disc's TOC.
normalize_disc_path_for_launch() swapped any .cue for its same-named .bin
unconditionally, and every disc entry point (game.toml, --disc, the cached
disc.cfg, the launcher's Change Disc, the first-run dialog) went through it.
That discarded the cue's table of contents -- every CD-DA track and pregap
with it -- even though iso_reader.cpp has full multi-FILE cue support that
the swap defeated before it was ever reached. In the other direction,
picking a redump audio-track bin mounted that track as the whole disc, which
cannot boot.
resolve_disc_path() (runtime/include/disc_path.h) now canonicalizes any pick:
.cue that resolves -> mount the cue (TOC intact)
.cue with a missing bin -> the payload it still names, else a
stem-matched sibling image
.bin/.iso/.img owned by a cue -> mount that cue
bare image, no cue -> mount it
identify_disc() resolves through the same code, so the header/serial/CRC32
verdict is read from the data track no matter which member was picked.
While here: the mount path and the verify path had two divergent private cue
parsers (quoted-only + case-sensitive vs quoted-or-bare + case-insensitive),
so they could disagree about the same file. Both now use one parser
(runtime/include/cue_sheet.h), which additionally handles CRLF, backslash
paths, and case-insensitive payload lookup for case-sensitive filesystems.
2. BIOS: the multi-BIOS rename made configs and dump folders incompatible.
SCPH*.toml name "US-PSX-SCPH1001.BIN" while every pre-existing dump folder,
bios.cfg and tools/regen_bios.sh default name "SCPH1001.BIN". Either
combination fataled with "cannot open BIOS file" despite the right ROM being
present. resolve_bios_rom() (recompiler/include/bios_rom_alias.h) matches on
the model token -- the last '-'-separated component of the stem -- so both
conventions resolve in both directions without a hardcoded alias table.
Applied at the config loader, the positional psxrecomp-bios CLI, and each
rung of the runtime's BIOS search.
The positional CLI also derived out_stem from the raw filename, so a
region-qualified ROM would have emitted US-PSX-SCPH1001_full.c -- a name
runtime.cmake cannot link. It now derives the model token.
Also fixes SCPH5552.toml, whose rom field omitted the bios/ directory that
its two siblings have.
Tests: test_disc_path_resolve (36 checks, five dump layouts) and
test_bios_rom_alias (15 checks, both directions + negative cases), both
registered in runtime/CMakeLists.txt. Registered the pre-existing
test_iso_reader_cdda, which was wired into no build.
Verified on real dumps: Ape Escape .cue and .bin both give
SCUS-94423 / NTSC-U / crc=C6F455BC; Tomba 2's multi-track dump gives
crc=1FB8C151 and a 2-track TOC from the .cue, the data bin, and the CD-DA
bin alike.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
78 lines
3.3 KiB
C++
78 lines
3.3 KiB
C++
// cue_sheet.h — the single cue-sheet parser for the runtime.
|
|
//
|
|
// A .cue is the authoritative table of contents for a PS1 disc dump: it names
|
|
// the backing BINARY file(s) and the TRACK/INDEX layout (data track, CD-DA
|
|
// audio tracks, pregaps). Everything that needs to understand a cue goes
|
|
// through here so the mount path (iso_reader.cpp), the identity/verify path
|
|
// (disc_identity.cpp) and the picked-path resolver (disc_path.cpp) can never
|
|
// disagree about what a given cue describes.
|
|
//
|
|
// Parsing is deliberately permissive about surface syntax (case, quoting,
|
|
// leading whitespace) and strict about semantics: a FILE whose type is not
|
|
// BINARY is reported rather than guessed at, because WAVE/MP3 payloads have no
|
|
// fixed sector geometry and mis-mapping the TOC is worse than refusing the
|
|
// image.
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace PSXRecompV4 {
|
|
|
|
// One FILE line, resolved against the cue's own directory.
|
|
struct CueFileRef {
|
|
std::string name; // exactly as written in the cue
|
|
std::filesystem::path path; // resolved (absolute where possible)
|
|
bool is_binary = false; // FILE type token was BINARY
|
|
bool exists = false; // resolved path is a real file
|
|
};
|
|
|
|
// One TRACK, with its INDEX times still expressed relative to the OWNING FILE
|
|
// (the cue's own convention). Converting to disc-relative LBAs needs each
|
|
// file's sector count, which only the mounting code knows.
|
|
struct CueTrackRef {
|
|
int number = 0;
|
|
bool is_audio = false;
|
|
size_t file_index = 0; // index into CueSheet::files
|
|
uint32_t index01 = 0; // track start, file-relative LBA
|
|
uint32_t index00 = 0; // pregap start, file-relative LBA
|
|
bool has_index00 = false;
|
|
};
|
|
|
|
struct CueSheet {
|
|
bool opened = false; // the .cue itself was readable
|
|
|
|
std::vector<CueFileRef> files; // in cue order
|
|
std::vector<CueTrackRef> tracks; // in cue order
|
|
|
|
// True when every FILE line named a BINARY payload that exists on disk —
|
|
// i.e. this cue can actually be mounted as written.
|
|
bool usable() const;
|
|
|
|
// True when at least one FILE line named a non-BINARY payload.
|
|
bool has_non_binary_file() const;
|
|
|
|
// Index of the file backing the first non-audio track, else 0. This is the
|
|
// file that carries SYSTEM.CNF / the ISO9660 header, so it is the one
|
|
// identity and CRC checks must read.
|
|
size_t data_file_index() const;
|
|
};
|
|
|
|
// Case-insensitive extension test. `dotted_ext` includes the dot, e.g. ".cue".
|
|
bool path_has_extension_ci(const std::filesystem::path& p, const char* dotted_ext);
|
|
|
|
// Resolve `name` (as written in a cue) against `dir`. Falls back to a
|
|
// case-insensitive directory scan when the literal name does not exist, so a
|
|
// redump cue written on Windows still mounts on a case-sensitive filesystem.
|
|
// Returns the literal resolution when nothing matches.
|
|
std::filesystem::path resolve_cue_relative_file(const std::filesystem::path& dir,
|
|
const std::string& name);
|
|
|
|
// Parse `cue_path`. A sheet whose `opened` is false could not be read at all.
|
|
CueSheet parse_cue_sheet(const std::filesystem::path& cue_path);
|
|
|
|
} // namespace PSXRecompV4
|