From 8108a661fad9c7d11f8830236384517dd69dc925 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 3 Jun 2026 12:46:33 +0200 Subject: [PATCH] fix: rewrite .cue FILE references that point to non-existent data files 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. --- .../java/com/dostalgia/UploadResource.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/main/java/com/dostalgia/UploadResource.java b/src/main/java/com/dostalgia/UploadResource.java index 340396e..8b202b1 100644 --- a/src/main/java/com/dostalgia/UploadResource.java +++ b/src/main/java/com/dostalgia/UploadResource.java @@ -80,6 +80,13 @@ public class UploadResource { + " — 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 String mainExe = findMainExe(extractDir); @@ -404,6 +411,66 @@ public class UploadResource { ".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. * Returns relative paths (with forward slashes) sorted alphabetically. */ private List findCdImages(Path dir) throws IOException {