From acab8db4fc72cd553dd2d65b11d0b8512e242594 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 21 Mar 2019 13:49:44 +0300 Subject: [PATCH] UnpackTool --- src/main/java/lwjake2/UnpackTool.java | 103 ++++++++++++++++++ .../lwjake2/qcommon/BaseQ2FileSystem.java | 33 +++++- 2 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/main/java/lwjake2/UnpackTool.java diff --git a/src/main/java/lwjake2/UnpackTool.java b/src/main/java/lwjake2/UnpackTool.java new file mode 100644 index 0000000..8528d45 --- /dev/null +++ b/src/main/java/lwjake2/UnpackTool.java @@ -0,0 +1,103 @@ +package lwjake2; + +import lombok.Value; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.*; + +@Slf4j +@UtilityClass +public class UnpackTool { + + private static final String READ_ONLY = "r"; + private static Map listPakFiles = new HashMap<>(); + private static Map pakFiles = new HashMap<>(); + + private static RandomAccessFile getPak(String pakName) { + RandomAccessFile raf; + + if (!pakFiles.containsKey(pakName)) { + try { + raf = new RandomAccessFile(pakName, READ_ONLY); + } catch (FileNotFoundException e) { + log.error("Read file error: {}", e.getMessage()); + raf = null; + } + + pakFiles.put(pakName, raf); + } else { + raf = pakFiles.get(pakName); + } + + return raf; + } + + public static void add(Entry entry) { + listPakFiles.put(entry.getName(), entry); + } + + public static void printList() { + listPakFiles.values().stream() + .sorted((o1, o2) -> { + final int result = o1.getPakName().compareTo(o2.getPakName()); + if (result == 0) { + return o1.getName().compareTo(o2.getName()); + } else { + return result; + } + }) + .forEach(entry -> log.info("{}: {}", entry.getPakName(), entry.getName())); + } + + public static Collection list() { + return listPakFiles.values(); + } + + public static Entry get(String name) { + return listPakFiles.get(name); + } + + @Value + public static class Entry { + private String name; + private int pos; + private long size; + private String pakName; + + public Entry(String name, int pos, long size, String pakName) { + int idx; + if ((idx = name.indexOf('\0')) != -1) { + this.name = name.substring(0, idx); + } else { + this.name = name; + } + + this.pos = pos; + this.size = size; + this.pakName = pakName; + } + + public byte[] getBytes() throws IOException { + RandomAccessFile pak = UnpackTool.getPak(pakName); + if (pak == null) { + return null; + } + + pak.seek(pos); + + byte[] result = new byte[(int) size]; + if (result.length < size) { + log.error("Can't cast long to int: size too big for intValue"); + return null; + } + + pak.readFully(result); + return result; + } + } +} diff --git a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java b/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java index 28150dc..41f64b8 100644 --- a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java +++ b/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java @@ -22,12 +22,14 @@ import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; +import lwjake2.UnpackTool; import lwjake2.game.Cmd; import lwjake2.game.cvar_t; import lwjake2.sys.Sys; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -487,7 +489,7 @@ public class BaseQ2FileSystem implements FileSystem { * Takes an explicit (not game tree related) path to a pak file. * * Loads the header and directory, adding the files at the beginning of the - * list so they override previous pack files. + * printList so they override previous pack files. */ private pack_t loadPackFile(String packfile) { dpackheader_t header; @@ -538,6 +540,12 @@ public class BaseQ2FileSystem implements FileSystem { entry.filelen = packhandle.getInt(); newfiles.put(entry.name.toLowerCase(), entry); + UnpackTool.add(new UnpackTool.Entry( + entry.name, + entry.filepos, + entry.filelen, + packfile + )); } } catch (IOException e) { @@ -564,7 +572,6 @@ public class BaseQ2FileSystem implements FileSystem { */ private void addGameDirectory(String dir) { int i; - searchpath_t search; pack_t pak; String pakfile; @@ -573,7 +580,7 @@ public class BaseQ2FileSystem implements FileSystem { // // add the directory to the search path // ensure fs_userdir is first in searchpath - search = new searchpath_t(); + searchpath_t search = new searchpath_t(); search.filename = dir; if (fs_searchpaths != null) { search.next = fs_searchpaths.next; @@ -600,6 +607,26 @@ public class BaseQ2FileSystem implements FileSystem { search.next = fs_searchpaths; fs_searchpaths = search; } + + UnpackTool.printList(); + + final File baseq2UnpackDir = new File(dir, "_unpack"); + baseq2UnpackDir.mkdirs(); + + UnpackTool.list().forEach(entry -> { + File file = new File(baseq2UnpackDir, entry.getName()); + if (file.exists()) { + return; + } + + file.getParentFile().mkdirs(); + try (FileOutputStream fos = new FileOutputStream(file)) { + log.info("Write '{}'...", entry.getName()); + fos.write(entry.getBytes()); + } catch (IOException e) { + log.error("Can't write file '{}': {}", entry.getName(), e.getMessage()); + } + }); } /*