📄 fs.java
字号:
/* * FS.java * Copyright (C) 2003 * * $Id: FS.java,v 1.15 2005/11/13 13:36:00 cawe Exp $ *//* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */package jake2.qcommon;import jake2.Defines;import jake2.Globals;import jake2.game.Cmd;import jake2.game.cvar_t;import jake2.sys.Sys;import java.io.*;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.channels.FileChannel;import java.util.*;/** * FS * * @author cwei */public final class FS extends Globals { /* * ================================================== * * QUAKE FILESYSTEM * * ================================================== */ 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 files; // with packfile_t entries } public static String fs_gamedir; private static String fs_userdir; public static cvar_t fs_basedir; public static cvar_t fs_cddir; public static cvar_t fs_gamedirvar; public static class filelink_t { String from; int fromlength; String to; } // with filelink_t entries public static List fs_links = new LinkedList(); public static class searchpath_t { String filename; pack_t pack; // only one of filename or pack will be used searchpath_t next; } public static searchpath_t fs_searchpaths; // without gamedirs public static searchpath_t fs_base_searchpaths; /* * All of Quake's data access is through a hierchal file system, but the * contents of the file system can be transparently merged from several * sources. * * The "base directory" is the path to the directory holding the quake.exe * and all game directories. The sys_* files pass this to host_init in * quakeparms_t->basedir. This can be overridden with the "-basedir" command * line parm to allow code debugging in a different directory. The base * directory is only used during filesystem initialization. * * The "game directory" is the first tree on the search path and directory * that all generated files (savegames, screenshots, demos, config files) * will be saved to. This can be overridden with the "-game" command line * parameter. The game directory can never be changed while quake is * executing. This is a precacution against having a malicious server * instruct clients to write files over areas they shouldn't. * */ /* * CreatePath * * Creates any directories needed to store the given filename. */ public static void CreatePath(String path) { int index = path.lastIndexOf('/'); // -1 if not found and 0 means write to root if (index > 0) { File f = new File(path.substring(0, index)); if (!f.mkdirs() && !f.isDirectory()) { Com.Printf("can't create path \"" + path + '"' + "\n"); } } } /* * FCloseFile * * For some reason, other dll's can't just call fclose() on files returned * by FS_FOpenFile... */ public static void FCloseFile(RandomAccessFile file) throws IOException { file.close(); } public static void FCloseFile(InputStream stream) throws IOException { stream.close(); } public static int FileLength(String filename) { searchpath_t search; String netpath; pack_t pak; int i; filelink_t link; file_from_pak = 0; // check for links first for (Iterator it = fs_links.iterator(); it.hasNext();) { link = (filelink_t) it.next(); if (filename.regionMatches(0, link.from, 0, link.fromlength)) { netpath = link.to + filename.substring(link.fromlength); File file = new File(netpath); if (file.canRead()) { Com.DPrintf("link file: " + netpath + '\n'); return (int) file.length(); } return -1; } } // search through the path, one element at a time for (search = fs_searchpaths; search != null; search = search.next) { // is the element a pak file? if (search.pack != null) { // look through all the pak file elements pak = search.pack; filename = filename.toLowerCase(); packfile_t entry = (packfile_t) pak.files.get(filename); if (entry != null) { // found it! file_from_pak = 1; Com.DPrintf("PackFile: " + pak.filename + " : " + filename + '\n'); // open a new file on the pakfile File file = new File(pak.filename); if (!file.canRead()) { Com.Error(Defines.ERR_FATAL, "Couldn't reopen " + pak.filename); } return entry.filelen; } } else { // check a file in the directory tree netpath = search.filename + '/' + filename; File file = new File(netpath); if (!file.canRead()) continue; Com.DPrintf("FindFile: " + netpath + '\n'); return (int) file.length(); } } Com.DPrintf("FindFile: can't find " + filename + '\n'); return -1; } public static int file_from_pak = 0; /* * FOpenFile * * Finds the file in the search path. returns a RadomAccesFile. Used for * streaming data out of either a pak file or a seperate file. */ public static RandomAccessFile FOpenFile(String filename) throws IOException { searchpath_t search; String netpath; pack_t pak; int i; filelink_t link; File file = null; file_from_pak = 0; // check for links first for (Iterator it = fs_links.iterator(); it.hasNext();) { link = (filelink_t) it.next(); // if (!strncmp (filename, link->from, link->fromlength)) if (filename.regionMatches(0, link.from, 0, link.fromlength)) { netpath = link.to + filename.substring(link.fromlength); file = new File(netpath); if (file.canRead()) { //Com.DPrintf ("link file: " + netpath +'\n'); return new RandomAccessFile(file, "r"); } return null; } } // // search through the path, one element at a time // for (search = fs_searchpaths; search != null; search = search.next) { // is the element a pak file? if (search.pack != null) { // look through all the pak file elements pak = search.pack; filename = filename.toLowerCase(); packfile_t entry = (packfile_t) pak.files.get(filename); if (entry != null) { // found it! file_from_pak = 1; //Com.DPrintf ("PackFile: " + pak.filename + " : " + // filename + '\n'); file = new File(pak.filename); if (!file.canRead()) Com.Error(Defines.ERR_FATAL, "Couldn't reopen " + pak.filename); if (pak.handle == null || !pak.handle.getFD().valid()) { // hold the pakfile handle open pak.handle = new RandomAccessFile(pak.filename, "r"); } // open a new file on the pakfile RandomAccessFile raf = new RandomAccessFile(file, "r"); raf.seek(entry.filepos); return raf; } } else { // check a file in the directory tree netpath = search.filename + '/' + filename; file = new File(netpath); if (!file.canRead()) continue; //Com.DPrintf("FindFile: " + netpath +'\n'); return new RandomAccessFile(file, "r"); } } //Com.DPrintf ("FindFile: can't find " + filename + '\n'); return null; } // read in blocks of 64k public static final int MAX_READ = 0x10000; /** * Read * * Properly handles partial reads */ public static void Read(byte[] buffer, int len, RandomAccessFile f) { int block, remaining; int offset = 0; int read = 0; boolean tries = true; // read in chunks for progress bar remaining = len; while (remaining != 0) { block = Math.min(remaining, MAX_READ); try { read = f.read(buffer, offset, block); } catch (IOException e) { Com.Error(Defines.ERR_FATAL, e.toString()); } if (read == 0) { Com.Error(Defines.ERR_FATAL, "FS_Read: 0 bytes read"); } else if (read == -1) { Com.Error(Defines.ERR_FATAL, "FS_Read: -1 bytes read"); } // // do some progress bar thing here... // remaining -= read; offset += read; } } /* * LoadFile * * Filename are reletive to the quake search path a null buffer will just * return the file content as byte[] */ public static byte[] LoadFile(String path) { RandomAccessFile file; byte[] buf = null; int len = 0; // TODO hack for bad strings (fuck \0) int index = path.indexOf('\0'); if (index != -1) path = path.substring(0, index); // look for it in the filesystem or pack files len = FileLength(path); if (len < 1) return null; try { file = FOpenFile(path); //Read(buf = new byte[len], len, h); buf = new byte[len]; file.readFully(buf); file.close(); } catch (IOException e) { Com.Error(Defines.ERR_FATAL, e.toString()); } return buf; } /* * LoadMappedFile * * Filename are reletive to the quake search path a null buffer will just * return the file content as ByteBuffer (memory mapped) */ public static ByteBuffer LoadMappedFile(String filename) { searchpath_t search; String netpath; pack_t pak; int i; filelink_t link; File file = null; int fileLength = 0; FileChannel channel = null; FileInputStream input = null; ByteBuffer buffer = null; file_from_pak = 0; try { // check for links first for (Iterator it = fs_links.iterator(); it.hasNext();) { link = (filelink_t) it.next(); if (filename.regionMatches(0, link.from, 0, link.fromlength)) { netpath = link.to + filename.substring(link.fromlength); file = new File(netpath); if (file.canRead()) { input = new FileInputStream(file); channel = input.getChannel(); fileLength = (int) channel.size(); buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); input.close(); return buffer; } return null; } } // // search through the path, one element at a time // for (search = fs_searchpaths; search != null; search = search.next) { // is the element a pak file? if (search.pack != null) { // look through all the pak file elements pak = search.pack; filename = filename.toLowerCase(); packfile_t entry = (packfile_t) pak.files.get(filename); if (entry != null) { // found it! file_from_pak = 1; //Com.DPrintf ("PackFile: " + pak.filename + " : " + // filename + '\n'); file = new File(pak.filename); if (!file.canRead()) Com.Error(Defines.ERR_FATAL, "Couldn't reopen " + pak.filename); if (pak.handle == null || !pak.handle.getFD().valid()) { // hold the pakfile handle open pak.handle = new RandomAccessFile(pak.filename, "r"); } // open a new file on the pakfile if (pak.backbuffer == null) { channel = pak.handle.getChannel(); pak.backbuffer = channel.map( FileChannel.MapMode.READ_ONLY, 0, pak.handle.length()); channel.close(); } pak.backbuffer.position(entry.filepos); buffer = pak.backbuffer.slice(); buffer.limit(entry.filelen); return buffer; } } else { // check a file in the directory tree netpath = search.filename + '/' + filename; file = new File(netpath); if (!file.canRead()) continue; //Com.DPrintf("FindFile: " + netpath +'\n'); input = new FileInputStream(file); channel = input.getChannel(); fileLength = (int) channel.size(); buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); input.close(); return buffer; } } } catch (Exception e) { } try { if (input != null) input.close(); else if (channel != null && channel.isOpen()) channel.close();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -