refac: PackFile
This commit is contained in:
@@ -23,6 +23,9 @@ import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.game.cvar_t;
|
||||
import lwjake2.sys.Sys;
|
||||
import ru.di9.lwjake2.PackFile;
|
||||
import ru.di9.lwjake2.PackFileEntry;
|
||||
import ru.di9.lwjake2.PackLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -30,12 +33,11 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* FS
|
||||
@@ -53,32 +55,6 @@ public final class FS extends Globals {
|
||||
* ==================================================
|
||||
*/
|
||||
|
||||
public static class packfile_t {
|
||||
static final int SIZE = 64;
|
||||
|
||||
static final int NAME_SIZE = 56;
|
||||
|
||||
String name; // char name[56]
|
||||
|
||||
int filepos, filelen;
|
||||
|
||||
public String toString() {
|
||||
return name + " [ length: " + filelen + " pos: " + filepos + " ]";
|
||||
}
|
||||
}
|
||||
|
||||
public static class pack_t {
|
||||
String filename;
|
||||
|
||||
RandomAccessFile handle;
|
||||
|
||||
ByteBuffer backbuffer;
|
||||
|
||||
int numfiles;
|
||||
|
||||
Hashtable<String, packfile_t> files; // with packfile_t entries
|
||||
}
|
||||
|
||||
public static String fs_gamedir;
|
||||
|
||||
private static String fs_userdir;
|
||||
@@ -103,7 +79,7 @@ public final class FS extends Globals {
|
||||
public static class searchpath_t {
|
||||
String filename;
|
||||
|
||||
pack_t pack; // only one of filename or pack will be used
|
||||
PackFile pack; // only one of filename or pack will be used
|
||||
|
||||
searchpath_t next;
|
||||
}
|
||||
@@ -166,7 +142,7 @@ public final class FS extends Globals {
|
||||
public static int FileLength(String filename) {
|
||||
searchpath_t search;
|
||||
String netpath;
|
||||
pack_t pak;
|
||||
PackFile pak;
|
||||
filelink_t link;
|
||||
|
||||
file_from_pak = 0;
|
||||
@@ -194,20 +170,20 @@ public final class FS extends Globals {
|
||||
// look through all the pak file elements
|
||||
pak = search.pack;
|
||||
filename = filename.toLowerCase();
|
||||
packfile_t entry = pak.files.get(filename);
|
||||
PackFileEntry entry = pak.getFiles().get(filename);
|
||||
|
||||
if (entry != null) {
|
||||
// found it!
|
||||
file_from_pak = 1;
|
||||
Com.DPrintf("PackFile: " + pak.filename + " : " + filename
|
||||
Com.DPrintf("PackFile: " + pak.getFilename() + " : " + filename
|
||||
+ '\n');
|
||||
// open a new file on the pakfile
|
||||
File file = new File(pak.filename);
|
||||
File file = new File(pak.getFilename());
|
||||
if (!file.canRead()) {
|
||||
Com.Error(Defines.ERR_FATAL, "Couldn't reopen "
|
||||
+ pak.filename);
|
||||
+ pak.getFilename());
|
||||
}
|
||||
return entry.filelen;
|
||||
return entry.getFileLen();
|
||||
}
|
||||
} else {
|
||||
// check a file in the directory tree
|
||||
@@ -238,7 +214,7 @@ public final class FS extends Globals {
|
||||
throws IOException {
|
||||
searchpath_t search;
|
||||
String netpath;
|
||||
pack_t pak;
|
||||
PackFile pak;
|
||||
filelink_t link;
|
||||
File file = null;
|
||||
|
||||
@@ -269,25 +245,25 @@ public final class FS extends Globals {
|
||||
// look through all the pak file elements
|
||||
pak = search.pack;
|
||||
filename = filename.toLowerCase();
|
||||
packfile_t entry = pak.files.get(filename);
|
||||
PackFileEntry entry = pak.getFiles().get(filename);
|
||||
|
||||
if (entry != null) {
|
||||
// found it!
|
||||
file_from_pak = 1;
|
||||
//Com.DPrintf ("PackFile: " + pak.filename + " : " +
|
||||
// filename + '\n');
|
||||
file = new File(pak.filename);
|
||||
file = new File(pak.getFilename());
|
||||
if (!file.canRead())
|
||||
Com.Error(Defines.ERR_FATAL, "Couldn't reopen "
|
||||
+ pak.filename);
|
||||
if (pak.handle == null || !pak.handle.getFD().valid()) {
|
||||
+ pak.getFilename());
|
||||
if (pak.getHandle() == null || !pak.getHandle().getFD().valid()) {
|
||||
// hold the pakfile handle open
|
||||
pak.handle = new RandomAccessFile(pak.filename, "r");
|
||||
pak.setHandle(new RandomAccessFile(pak.getFilename(), "r"));
|
||||
}
|
||||
// open a new file on the pakfile
|
||||
|
||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
raf.seek(entry.filepos);
|
||||
raf.seek(entry.getFilePos());
|
||||
|
||||
return raf;
|
||||
}
|
||||
@@ -390,7 +366,7 @@ public final class FS extends Globals {
|
||||
public static ByteBuffer LoadMappedFile(String filename) {
|
||||
searchpath_t search;
|
||||
String netpath;
|
||||
pack_t pak;
|
||||
PackFile pak;
|
||||
filelink_t link;
|
||||
File file = null;
|
||||
|
||||
@@ -431,32 +407,32 @@ public final class FS extends Globals {
|
||||
// look through all the pak file elements
|
||||
pak = search.pack;
|
||||
filename = filename.toLowerCase();
|
||||
packfile_t entry = pak.files.get(filename);
|
||||
PackFileEntry entry = pak.getFiles().get(filename);
|
||||
|
||||
if (entry != null) {
|
||||
// found it!
|
||||
file_from_pak = 1;
|
||||
//Com.DPrintf ("PackFile: " + pak.filename + " : " +
|
||||
// filename + '\n');
|
||||
file = new File(pak.filename);
|
||||
file = new File(pak.getFilename());
|
||||
if (!file.canRead())
|
||||
Com.Error(Defines.ERR_FATAL, "Couldn't reopen "
|
||||
+ pak.filename);
|
||||
if (pak.handle == null || !pak.handle.getFD().valid()) {
|
||||
+ pak.getFilename());
|
||||
if (pak.getHandle() == null || !pak.getHandle().getFD().valid()) {
|
||||
// hold the pakfile handle open
|
||||
pak.handle = new RandomAccessFile(pak.filename, "r");
|
||||
pak.setHandle(new RandomAccessFile(pak.getFilename(), "r"));
|
||||
}
|
||||
// open a new file on the pakfile
|
||||
if (pak.backbuffer == null) {
|
||||
channel = pak.handle.getChannel();
|
||||
pak.backbuffer = channel.map(
|
||||
if (pak.getBackBuffer() == null) {
|
||||
channel = pak.getHandle().getChannel();
|
||||
pak.setBackBuffer(channel.map(
|
||||
FileChannel.MapMode.READ_ONLY, 0,
|
||||
pak.handle.length());
|
||||
pak.getHandle().length()));
|
||||
channel.close();
|
||||
}
|
||||
pak.backbuffer.position(entry.filepos);
|
||||
buffer = pak.backbuffer.slice();
|
||||
buffer.limit(entry.filelen);
|
||||
pak.getBackBuffer().position(entry.getFilePos());
|
||||
buffer = pak.getBackBuffer().slice();
|
||||
buffer.limit(entry.getFileLen());
|
||||
return buffer;
|
||||
}
|
||||
} else {
|
||||
@@ -508,86 +484,6 @@ public final class FS extends Globals {
|
||||
|
||||
static final int MAX_FILES_IN_PACK = 4096;
|
||||
|
||||
// buffer for C-Strings char[56]
|
||||
static byte[] tmpText = new byte[packfile_t.NAME_SIZE];
|
||||
|
||||
/*
|
||||
* LoadPackFile
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static pack_t LoadPackFile(String packfile) {
|
||||
|
||||
dpackheader_t header;
|
||||
Hashtable<String, packfile_t> newfiles;
|
||||
RandomAccessFile file;
|
||||
int numpackfiles = 0;
|
||||
pack_t pack = null;
|
||||
// unsigned checksum;
|
||||
//
|
||||
try {
|
||||
file = new RandomAccessFile(packfile, "r");
|
||||
FileChannel fc = file.getChannel();
|
||||
ByteBuffer packhandle = fc.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
|
||||
packhandle.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
fc.close();
|
||||
|
||||
if (packhandle == null || packhandle.limit() < 1)
|
||||
return null;
|
||||
//
|
||||
header = new dpackheader_t();
|
||||
header.ident = packhandle.getInt();
|
||||
header.dirofs = packhandle.getInt();
|
||||
header.dirlen = packhandle.getInt();
|
||||
|
||||
if (header.ident != IDPAKHEADER)
|
||||
Com.Error(Defines.ERR_FATAL, packfile + " is not a packfile");
|
||||
|
||||
numpackfiles = header.dirlen / packfile_t.SIZE;
|
||||
|
||||
if (numpackfiles > MAX_FILES_IN_PACK)
|
||||
Com.Error(Defines.ERR_FATAL, packfile + " has " + numpackfiles
|
||||
+ " files");
|
||||
|
||||
newfiles = new Hashtable<String, packfile_t>(numpackfiles);
|
||||
|
||||
packhandle.position(header.dirofs);
|
||||
|
||||
// parse the directory
|
||||
packfile_t entry = null;
|
||||
|
||||
for (int i = 0; i < numpackfiles; i++) {
|
||||
packhandle.get(tmpText);
|
||||
|
||||
entry = new packfile_t();
|
||||
entry.name = new String(tmpText).trim();
|
||||
entry.filepos = packhandle.getInt();
|
||||
entry.filelen = packhandle.getInt();
|
||||
|
||||
newfiles.put(entry.name.toLowerCase(), entry);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Com.DPrintf(e.getMessage() + '\n');
|
||||
return null;
|
||||
}
|
||||
|
||||
pack = new pack_t();
|
||||
pack.filename = new String(packfile);
|
||||
pack.handle = file;
|
||||
pack.numfiles = numpackfiles;
|
||||
pack.files = newfiles;
|
||||
|
||||
Com.Printf("Added packfile " + packfile + " (" + numpackfiles
|
||||
+ " files)\n");
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/*
|
||||
* AddGameDirectory
|
||||
*
|
||||
@@ -597,7 +493,7 @@ public final class FS extends Globals {
|
||||
static void AddGameDirectory(String dir) {
|
||||
int i;
|
||||
searchpath_t search;
|
||||
pack_t pak;
|
||||
PackFile pak;
|
||||
String pakfile;
|
||||
|
||||
fs_gamedir = new String(dir);
|
||||
@@ -622,9 +518,17 @@ public final class FS extends Globals {
|
||||
if (!(new File(pakfile).canRead()))
|
||||
continue;
|
||||
|
||||
pak = LoadPackFile(pakfile);
|
||||
if (pak == null)
|
||||
continue;
|
||||
try {
|
||||
Optional<PackFile> opt = PackLoader.INSTANCE.loadFromFile(pakfile);
|
||||
if (opt.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
pak = opt.get();
|
||||
Com.Printf("Added packfile " + pak.getFilename() + " (" + pak.getNumFiles()
|
||||
+ " files)\n");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
search = new searchpath_t();
|
||||
search.pack = pak;
|
||||
@@ -695,13 +599,13 @@ public final class FS extends Globals {
|
||||
while (fs_searchpaths != fs_base_searchpaths) {
|
||||
if (fs_searchpaths.pack != null) {
|
||||
try {
|
||||
fs_searchpaths.pack.handle.close();
|
||||
fs_searchpaths.pack.getHandle().close();
|
||||
} catch (IOException e) {
|
||||
Com.DPrintf(e.getMessage() + '\n');
|
||||
}
|
||||
// clear the hashtable
|
||||
fs_searchpaths.pack.files.clear();
|
||||
fs_searchpaths.pack.files = null;
|
||||
fs_searchpaths.pack.getFiles().clear();
|
||||
fs_searchpaths.pack.setFiles(null);
|
||||
fs_searchpaths.pack = null;
|
||||
}
|
||||
next = fs_searchpaths.next;
|
||||
@@ -840,7 +744,7 @@ public final class FS extends Globals {
|
||||
if (s == fs_base_searchpaths)
|
||||
Com.Printf("----------\n");
|
||||
if (s.pack != null)
|
||||
Com.Printf(s.pack.filename + " (" + s.pack.numfiles
|
||||
Com.Printf(s.pack.getFilename() + " (" + s.pack.getNumFiles()
|
||||
+ " files)\n");
|
||||
else
|
||||
Com.Printf(s.filename + '\n');
|
||||
|
||||
53
src/ru/di9/lwjake2/PackFile.java
Normal file
53
src/ru/di9/lwjake2/PackFile.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package ru.di9.lwjake2;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
|
||||
public class PackFile {
|
||||
private final String filename;
|
||||
private final int numFiles;
|
||||
|
||||
private Map<String, PackFileEntry> files;
|
||||
private RandomAccessFile handle;
|
||||
private ByteBuffer backBuffer;
|
||||
|
||||
public PackFile(String filename, RandomAccessFile handle, int numFiles, Map<String, PackFileEntry> files) {
|
||||
this.filename = filename;
|
||||
this.handle = handle;
|
||||
this.numFiles = numFiles;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public int getNumFiles() {
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
public RandomAccessFile getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
public void setHandle(RandomAccessFile handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public Map<String, PackFileEntry> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public void setFiles(Map<String, PackFileEntry> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public ByteBuffer getBackBuffer() {
|
||||
return backBuffer;
|
||||
}
|
||||
|
||||
public void setBackBuffer(ByteBuffer backBuffer) {
|
||||
this.backBuffer = backBuffer;
|
||||
}
|
||||
}
|
||||
30
src/ru/di9/lwjake2/PackFileEntry.java
Normal file
30
src/ru/di9/lwjake2/PackFileEntry.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package ru.di9.lwjake2;
|
||||
|
||||
public class PackFileEntry {
|
||||
private final String name;
|
||||
private final int filePos;
|
||||
private final int fileLen;
|
||||
|
||||
public PackFileEntry(String name, int filePos, int fileLen) {
|
||||
this.name = name;
|
||||
this.filePos = filePos;
|
||||
this.fileLen = fileLen;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getFilePos() {
|
||||
return filePos;
|
||||
}
|
||||
|
||||
public int getFileLen() {
|
||||
return fileLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " [ length: " + fileLen + " pos: " + filePos + " ]";
|
||||
}
|
||||
}
|
||||
74
src/ru/di9/lwjake2/PackLoader.java
Normal file
74
src/ru/di9/lwjake2/PackLoader.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package ru.di9.lwjake2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PackLoader {
|
||||
public static final PackLoader INSTANCE = new PackLoader();
|
||||
|
||||
private static final String FLAG_READ_ONLY = "r";
|
||||
private static final int IDPAKHEADER = (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P');
|
||||
private static final int SIZE = 64;
|
||||
private static final int MAX_FILES_IN_PACK = 4096;
|
||||
private static final int NAME_SIZE = 56;
|
||||
|
||||
/*
|
||||
* LoadPackFile
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public Optional<PackFile> loadFromFile(String file) throws IOException {
|
||||
RandomAccessFile raf = new RandomAccessFile(file, FLAG_READ_ONLY);
|
||||
ByteBuffer packHandle;
|
||||
try(FileChannel channel = raf.getChannel()) {
|
||||
packHandle = channel.map(FileChannel.MapMode.READ_ONLY, 0, raf.length());
|
||||
if (packHandle == null || packHandle.limit() < 1) {
|
||||
raf.close();
|
||||
return Optional.empty();
|
||||
}
|
||||
packHandle.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
int headerIdent = packHandle.getInt();
|
||||
if (headerIdent != IDPAKHEADER) {
|
||||
raf.close();
|
||||
throw new IOException(file + " is not a packfile");
|
||||
}
|
||||
|
||||
int headerDirofs = packHandle.getInt();
|
||||
int headerDirlen = packHandle.getInt();
|
||||
|
||||
int numPackFiles = headerDirlen / SIZE;
|
||||
if (numPackFiles > MAX_FILES_IN_PACK) {
|
||||
raf.close();
|
||||
throw new IOException(file + " has " + numPackFiles + " files");
|
||||
}
|
||||
|
||||
Map<String, PackFileEntry> newFiles = new HashMap<>(numPackFiles);
|
||||
packHandle.position(headerDirofs);
|
||||
|
||||
PackFileEntry entry;
|
||||
byte[] tmpBuff = new byte[NAME_SIZE];
|
||||
for (int i = 0; i < numPackFiles; i++) {
|
||||
packHandle.get(tmpBuff);
|
||||
|
||||
String name = new String(tmpBuff).trim();
|
||||
int filePos = packHandle.getInt();
|
||||
int fileLen = packHandle.getInt();
|
||||
entry = new PackFileEntry(name, filePos, fileLen);
|
||||
|
||||
newFiles.put(entry.getName().toLowerCase(), entry);
|
||||
}
|
||||
|
||||
return Optional.of(new PackFile(file, raf, numPackFiles, newFiles));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user