From 542db6a916fb255ed304fffb2b4661d0c5f005e0 Mon Sep 17 00:00:00 2001 From: David Alvarez Date: Wed, 27 May 2026 10:36:44 +0200 Subject: [PATCH] Fix: handle DOS games in subdirectories inside .jsdos bundles When a ZIP contains game files in a subdirectory (e.g. doomiido/), findMainExe() correctly finds the executable but the bundle autoexec was using just the filename, causing DOSBox 'Illegal command' error. - Use extractDir.relativize() to compute the relative exe path - buildDosboxConf() now adds 'cd dirname' before running the exe - buildJsdosJson() uses 'cd dirname && exe' for multi-line script - Fix applies to both sockdrive and standard bundle paths --- .../java/com/dostalgia/UploadResource.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/dostalgia/UploadResource.java b/src/main/java/com/dostalgia/UploadResource.java index 8c27c5f..b489729 100644 --- a/src/main/java/com/dostalgia/UploadResource.java +++ b/src/main/java/com/dostalgia/UploadResource.java @@ -88,7 +88,7 @@ public class UploadResource { // Write dosbox.conf (full config, not just autoexec) Path jsdos = gameDir.resolve(".jsdos"); Files.createDirectories(jsdos); - String relExe = Path.of(mainExe).getFileName().toString(); + String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('\\', '/'); String conf = buildDosboxConf(relExe); Files.writeString(jsdos.resolve("dosbox.conf"), conf); Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe)); @@ -216,7 +216,7 @@ public class UploadResource { // Create .jsdos config (full config, not just autoexec) Path jsdos = tmpBundle.resolve(".jsdos"); Files.createDirectories(jsdos); - String relExe = Path.of(mainExe).getFileName().toString(); + String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('\\', '/'); String conf = buildDosboxConf(relExe); Files.writeString(jsdos.resolve("dosbox.conf"), conf); Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe)); @@ -247,9 +247,18 @@ public class UploadResource { * translate physical key presses into game input. */ private byte[] buildJsdosJson(String relExe) { + // Split into directory and executable components for subdirectory support + String dir = ""; + String exe = relExe; + int idx = relExe.lastIndexOf('/'); + if (idx >= 0) { + dir = relExe.substring(0, idx); + exe = relExe.substring(idx + 1); + } + String script = (dir.isEmpty() ? "" : "cd " + dir + " && ") + exe; String json = "{" + "\"autoexec\":{" - + "\"options\":{\"script\":{\"value\":\"" + escapeJson(relExe) + "\"}}" + + "\"options\":{\"script\":{\"value\":\"" + escapeJson(script) + "\"}}" + "}," + "\"output\":{" + "\"options\":{\"autolock\":{\"value\":true}}}" @@ -262,6 +271,15 @@ public class UploadResource { } private String buildDosboxConf(String relExe) { + // Split into directory and executable components for subdirectory support + String dir = ""; + String exe = relExe; + int idx = relExe.lastIndexOf('/'); + if (idx >= 0) { + dir = relExe.substring(0, idx); + exe = relExe.substring(idx + 1); + } + return "[sdl]\n" + "autolock=true\n" + "usescancodes=true\n" @@ -291,7 +309,8 @@ public class UploadResource { + "mount c .\n" + "c:\n" + "cls\n" - + relExe + "\n"; + + (dir.isEmpty() ? "" : "cd " + dir + "\n") + + exe + "\n"; } /**