2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
24 * Unpack -- a completely non-object oriented utility...
31 static final int IDPAKHEADER = (('K'<<24)+('C'<<16)+('A'<<8)+'P');
33 static int intSwap(int i) {
41 return (a << 24) + (b << 16) + (c << 8) + d;
44 static boolean patternMatch (String pattern, String s) {
48 if (pattern.equals(s)) {
52 // fairly lame single wildcard matching
53 index = pattern.indexOf('*');
57 if (!pattern.regionMatches(0, s, 0, index)) {
61 index += 1; // skip the *
62 remaining = pattern.length() - index;
63 if (s.length() < remaining) {
67 if (!pattern.regionMatches(index, s, s.length()-remaining, remaining)) {
75 System.out.println ("Usage: unpack <packfile> <match> <basedir>");
76 System.out.println (" or: unpack -list <packfile>");
77 System.out.println ("<match> may contain a single * wildcard");
81 public static void main (String[] args) {
87 byte[] name = new byte[56];
91 RandomAccessFile readLump;
92 DataInputStream directory;
96 if (args.length == 2) {
97 if (!args[0].equals("-list")) {
102 } else if (args.length == 3) {
112 // one stream to read the directory
113 directory = new DataInputStream(new FileInputStream(pakName));
115 // another to read lumps
116 readLump = new RandomAccessFile(pakName, "r");
119 ident = intSwap(directory.readInt());
120 dirofs = intSwap(directory.readInt());
121 dirlen = intSwap(directory.readInt());
123 if (ident != IDPAKHEADER) {
124 System.out.println ( pakName + " is not a pakfile.");
128 // read the directory
129 directory.skipBytes (dirofs - 12);
130 numLumps = dirlen / 64;
132 System.out.println (numLumps + " lumps in " + pakName);
134 for (i = 0 ; i < numLumps ; i++) {
135 directory.readFully(name);
136 filepos = intSwap(directory.readInt());
137 filelen = intSwap(directory.readInt());
139 nameString = new String (name, 0);
140 // chop to the first 0 byte
141 nameString = nameString.substring (0, nameString.indexOf(0));
143 if (pattern == null) {
145 System.out.println (nameString + " : " + filelen + "bytes");
146 } else if (patternMatch (pattern, nameString) ) {
148 DataOutputStream writeLump;
149 byte[] buffer = new byte[filelen];
150 StringBuffer fixedString;
154 System.out.println ("Unpaking " + nameString + " " + filelen
158 readLump.seek(filepos);
159 readLump.readFully(buffer);
161 // quake uses forward slashes, but java requires
162 // they only by the host's seperator, which
163 // varies from win to unix
164 fixedString = new StringBuffer (args[2] + File.separator + nameString);
165 for (index = 0 ; index < fixedString.length() ; index++) {
166 if (fixedString.charAt(index) == '/') {
167 fixedString.setCharAt(index, File.separatorChar);
170 finalName = fixedString.toString ();
172 index = finalName.lastIndexOf(File.separatorChar);
177 finalPath = finalName.substring(0, index);
178 writePath = new File (finalPath);
182 writeFile = new File (finalName);
183 writeLump = new DataOutputStream ( new FileOutputStream(writeFile) );
184 writeLump.write(buffer);
193 } catch (IOException e) {
194 System.out.println ( e.toString() );