fix: rewrite .cue FILE references that point to non-existent data files
Build & Deploy / build-and-deploy (push) Successful in 12s

CloneCD rips generate a .cue that references DOTT.bin but the actual
data file is DOTT.img. DOSBox fails to mount the CD when the referenced
file doesn't exist, causing 'Illegal command' for executables on the CD.

Now before bundle creation, we scan all .cue files and fix any FILE line
that points to a missing data file by rewriting it to reference .img
or .bin files actually present in the same directory.
This commit is contained in:
Hermes Agent
2026-06-03 12:46:33 +02:00
parent 57842abe0d
commit 8108a661fa
@@ -80,6 +80,13 @@ public class UploadResource {
+ " — continuing (cd in autoexec handles subdirs)"); + " — continuing (cd in autoexec handles subdirs)");
} }
// Fix .cue files that reference non-existent data files (e.g. CloneCD)
try {
fixCueReferences(extractDir);
} catch (Exception e) {
LOG.warning("Failed to fix cue references: " + e.getMessage());
}
// Find main executable // Find main executable
String mainExe = findMainExe(extractDir); String mainExe = findMainExe(extractDir);
@@ -404,6 +411,66 @@ public class UploadResource {
".iso", ".cue", ".img", ".ccd", ".bin" ".iso", ".cue", ".img", ".ccd", ".bin"
); );
/**
* Fix .cue files that reference non-existent data files.
* CloneCD rips often generate a .cue that says FILE "DOTT.bin" BINARY
* but the actual data file is DOTT.img. DOSBox can't load the .cue
* when the referenced file doesn't exist.
*/
private static void fixCueReferences(Path extractDir) throws IOException {
try (var walk = Files.walk(extractDir)) {
walk.filter(Files::isRegularFile)
.filter(f -> f.getFileName().toString().toLowerCase().endsWith(".cue"))
.forEach(f -> {
try {
fixOneCue(f);
} catch (IOException e) {
LOG.warning("Failed to fix cue file " + f + ": " + e.getMessage());
}
});
}
}
private static void fixOneCue(Path cueFile) throws IOException {
String content = Files.readString(cueFile);
Path dir = cueFile.getParent();
// Find the FILE line: FILE "somefile.bin" BINARY
// The pattern: FILE "..." (anything between quotes)
java.util.regex.Matcher m = java.util.regex.Pattern
.compile("FILE\\s+\"([^\"]+)\"", java.util.regex.Pattern.CASE_INSENSITIVE)
.matcher(content);
if (!m.find()) return; // no FILE line, nothing to fix
String referenced = m.group(1);
Path refPath = dir.resolve(referenced);
if (Files.exists(refPath)) return; // referenced file exists, cue is fine
// Referenced file doesn't exist — look for .img or .bin in same directory
Path replacement = findDataFile(dir);
if (replacement == null) return; // nothing to replace with
// Rewrite the FILE line with the actual file
String actualName = replacement.getFileName().toString();
content = content.substring(0, m.start(1)) + actualName + content.substring(m.end(1));
Files.writeString(cueFile, content);
LOG.info("Fixed cue " + cueFile.getFileName() + ": referenced '" + referenced
+ "' → '" + actualName + "'");
}
/** Find a .img or .bin file in the directory that could be the data file. */
private static Path findDataFile(Path dir) throws IOException {
try (var files = Files.list(dir)) {
return files.filter(Files::isRegularFile)
.filter(f -> {
String n = f.getFileName().toString().toLowerCase();
return n.endsWith(".img") || n.endsWith(".bin");
})
.findFirst()
.orElse(null);
}
}
/** Find mountable CD image files in the extracted game directory. /** Find mountable CD image files in the extracted game directory.
* Returns relative paths (with forward slashes) sorted alphabetically. */ * Returns relative paths (with forward slashes) sorted alphabetically. */
private List<String> findCdImages(Path dir) throws IOException { private List<String> findCdImages(Path dir) throws IOException {