Revert "feat: add Sierra game bundle patcher and API endpoint"
Build & Deploy / build-and-deploy (push) Successful in 20s
Build & Deploy / build-and-deploy (push) Successful in 20s
This reverts commit 5abc066178.
This commit is contained in:
@@ -131,23 +131,6 @@ public class GameResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Patch a Sierra game bundle to fix common file layout issues
|
|
||||||
* (INTERP.ERR paths, RESOURCE.CFG directories).
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("/{id}/patch-sierra")
|
|
||||||
public Response patchSierra(@PathParam("id") String id) {
|
|
||||||
try {
|
|
||||||
var patched = svc.patchSierraGame(id);
|
|
||||||
return Response.ok(Map.of("patched", patched)).build();
|
|
||||||
} catch (NoSuchFileException e) {
|
|
||||||
return Response.status(404).entity(Map.of("error", "Game not found")).build();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return Response.serverError().entity(Map.of("error", e.getMessage())).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{id}/download")
|
@Path("/{id}/download")
|
||||||
@Produces("application/zip")
|
@Produces("application/zip")
|
||||||
|
|||||||
@@ -322,154 +322,5 @@ public class GameService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Patch a .jsdos bundle for Sierra games that have file layout issues:
|
|
||||||
* - INTERP.ERR(C) in a subdirectory instead of root (causes "Can't find" errors)
|
|
||||||
* - RESOURCE.CFG directory paths pointing to wrong locations
|
|
||||||
* Returns the list of files that were modified.
|
|
||||||
*/
|
|
||||||
public List<String> patchSierraGame(String id) throws IOException {
|
|
||||||
Game game = load(id);
|
|
||||||
Path bundlePath = gamesDir.resolve(game.getBundleFile());
|
|
||||||
if (!Files.exists(bundlePath)) {
|
|
||||||
throw new NoSuchFileException("Bundle not found: " + game.getBundleFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
Path tmpPath = bundlePath.resolveSibling(bundlePath.getFileName() + ".patchtmp");
|
|
||||||
List<String> patched = new ArrayList<>();
|
|
||||||
|
|
||||||
try (var zis = new java.util.zip.ZipInputStream(Files.newInputStream(bundlePath));
|
|
||||||
var zos = new java.util.zip.ZipOutputStream(Files.newOutputStream(tmpPath))) {
|
|
||||||
|
|
||||||
// First pass: read all entries to find INTERP files in subdirs
|
|
||||||
// We can't buffer the whole zip, so we do the copy in one pass
|
|
||||||
// and apply known fixes on the fly.
|
|
||||||
|
|
||||||
// Read the RESOURCE.CFG for Sierra directory detection
|
|
||||||
// We do this by pre-scanning the zip (streaming approach)
|
|
||||||
|
|
||||||
java.util.zip.ZipEntry entry;
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
|
||||||
String name = entry.getName();
|
|
||||||
zos.putNextEntry(new java.util.zip.ZipEntry(name));
|
|
||||||
|
|
||||||
if (name.equals("RESOURCE.CFG")) {
|
|
||||||
// Read, patch, write
|
|
||||||
byte[] content = zis.readAllBytes();
|
|
||||||
String text = new String(content, java.nio.charset.StandardCharsets.ISO_8859_1);
|
|
||||||
String original = text;
|
|
||||||
|
|
||||||
// Fix directory paths pointing to a subdir when resources are at root
|
|
||||||
text = text.replaceAll("(?m)^directory\\s*=\\\\?.+", "directory = .");
|
|
||||||
text = text.replaceAll("(?m)^audio\\s*=\\s*[A-Za-z]:\\\\?.+", "audio = .");
|
|
||||||
text = text.replaceAll("(?m)^sync\\s*=\\s*[A-Za-z]:\\\\?.+", "sync = .");
|
|
||||||
text = text.replaceAll("(?m)^movieDir\\s*=\\s*[A-Za-z]:\\\\?.+", "movieDir = .\\\\SEQ");
|
|
||||||
text = text.replaceAll("(?m)^patchDir\\s*=\\s*[A-Za-z]:\\\\?.+", "patchDir = .");
|
|
||||||
|
|
||||||
if (!text.equals(original)) {
|
|
||||||
patched.add("RESOURCE.CFG (fixed paths)");
|
|
||||||
zos.write(text.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1));
|
|
||||||
} else {
|
|
||||||
zos.write(content);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For all other files, check if we need to add INTERP.ERR(C) copies
|
|
||||||
zis.transferTo(zos);
|
|
||||||
}
|
|
||||||
zos.closeEntry();
|
|
||||||
zis.closeEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second pass: scan for INTERP files in subdirectories
|
|
||||||
// We need to re-read the zip for this. Use a clean approach.
|
|
||||||
}
|
|
||||||
|
|
||||||
// If RESOURCE.CFG was not patched, check for INTERP.ERR and add it
|
|
||||||
boolean needsInterpFix = false;
|
|
||||||
String interpSource = null;
|
|
||||||
|
|
||||||
// Re-scan the original bundle for INTERP files in subdirs
|
|
||||||
try (var zis = new java.util.zip.ZipInputStream(Files.newInputStream(bundlePath))) {
|
|
||||||
java.util.zip.ZipEntry entry;
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
|
||||||
String name = entry.getName();
|
|
||||||
if (!name.startsWith(".jsdos/") && name.contains("/") &&
|
|
||||||
(name.endsWith("/INTERP.ERR") || name.endsWith("/INTERP.ERRC"))) {
|
|
||||||
// Found an INTERP file in a subdirectory
|
|
||||||
String rootName = name.substring(name.lastIndexOf('/') + 1);
|
|
||||||
interpSource = name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
zis.closeEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interpSource != null) {
|
|
||||||
// Check if INTERP file already exists at root in the patched bundle
|
|
||||||
boolean hasRootInterp = false;
|
|
||||||
try (var zis = new java.util.zip.ZipInputStream(Files.newInputStream(tmpPath))) {
|
|
||||||
java.util.zip.ZipEntry entry;
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
|
||||||
String name = entry.getName();
|
|
||||||
if (name.equals("INTERP.ERR") || name.equals("INTERP.ERRC")) {
|
|
||||||
hasRootInterp = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
zis.closeEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasRootInterp) {
|
|
||||||
// Read the INTERP file from original bundle and append it
|
|
||||||
byte[] interpData = null;
|
|
||||||
try (var zis = new java.util.zip.ZipInputStream(Files.newInputStream(bundlePath))) {
|
|
||||||
java.util.zip.ZipEntry entry;
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
|
||||||
if (entry.getName().equals(interpSource)) {
|
|
||||||
interpData = zis.readAllBytes();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
zis.closeEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interpData != null) {
|
|
||||||
// Append to the patched bundle
|
|
||||||
String rootName = interpSource.substring(interpSource.lastIndexOf('/') + 1);
|
|
||||||
try (var zis2 = new java.util.zip.ZipInputStream(Files.newInputStream(tmpPath));
|
|
||||||
var tmp2 = new java.util.zip.ZipOutputStream(Files.newOutputStream(
|
|
||||||
tmpPath.resolveSibling(bundlePath.getFileName() + ".patchtmp2")))) {
|
|
||||||
java.util.zip.ZipEntry e;
|
|
||||||
while ((e = zis2.getNextEntry()) != null) {
|
|
||||||
tmp2.putNextEntry(new java.util.zip.ZipEntry(e.getName()));
|
|
||||||
zis2.transferTo(tmp2);
|
|
||||||
tmp2.closeEntry();
|
|
||||||
zis2.closeEntry();
|
|
||||||
}
|
|
||||||
// Add INTERP file at root
|
|
||||||
tmp2.putNextEntry(new java.util.zip.ZipEntry(rootName));
|
|
||||||
tmp2.write(interpData);
|
|
||||||
tmp2.closeEntry();
|
|
||||||
zis2.close();
|
|
||||||
tmp2.close();
|
|
||||||
}
|
|
||||||
Files.delete(tmpPath);
|
|
||||||
Path tmp2 = tmpPath.resolveSibling(bundlePath.getFileName() + ".patchtmp2");
|
|
||||||
Files.move(tmp2, tmpPath);
|
|
||||||
patched.add(rootName + " (copied from " + interpSource + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If nothing was patched, clean up and return empty
|
|
||||||
if (patched.isEmpty()) {
|
|
||||||
Files.deleteIfExists(tmpPath);
|
|
||||||
return patched;
|
|
||||||
}
|
|
||||||
|
|
||||||
Files.move(tmpPath, bundlePath, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
return patched;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getGamesDir() { return gamesDir; }
|
public Path getGamesDir() { return gamesDir; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user