UnpackTool
This commit is contained in:
103
src/main/java/lwjake2/UnpackTool.java
Normal file
103
src/main/java/lwjake2/UnpackTool.java
Normal file
@@ -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<String, Entry> listPakFiles = new HashMap<>();
|
||||
private static Map<String, RandomAccessFile> 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<Entry> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user