1 /*
2  * pakx.c -- pack file extraction tool.
3  * $Id: pakx.c 5787 2017-01-03 22:22:34Z sezero $
4  *
5  * Copyright (C) 1996-2001 Id Software, Inc.
6  * Copyright (C) 2010 Ozkan Sezer <sezero@users.sourceforge.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or (at
11  * your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * See the GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 #include "q_stdinc.h"
25 #include "compiler.h"
26 #include "arch_def.h"
27 #include "cmdlib.h"
28 #include "util_io.h"
29 #include "byteordr.h"
30 #include "pathutil.h"
31 #include "pakfile.h"
32 #include "pak.h"
33 #include "filenames.h"
34 
35 //======================================================================
36 
ExtractFile(pack_t * pak,const char * filename,const char * destdir)37 static void ExtractFile (pack_t *pak, const char *filename, const char *destdir)
38 {
39 	char	dest[1024], *dptr;
40 	int	i;
41 
42 	if (!destdir || !*destdir)
43 	{
44 		dptr = dest;
45 	}
46 	else
47 	{
48 		strcpy (dest, destdir);
49 		i = strlen (destdir);
50 		if (!IS_DIR_SEPARATOR(dest[i - 1]))
51 		{
52 			dest[i] = DIR_SEPARATOR_CHAR;
53 			dest[i + 1] = '\0';
54 		}
55 		dptr = strchr(dest, '\0');
56 	}
57 
58 	for (i = 0; i < pak->numfiles; i++)
59 	{
60 		if (!filename)
61 		{
62 			fseek (pak->handle, pak->files[i].filepos, SEEK_SET);
63 			strcpy (dptr, pak->files[i].name);
64 			dest[sizeof(dest) - 1] = '\0';
65 			printf ("%s --> %s\n", pak->files[i].name, dest);
66 			if (Q_WriteFileFromHandle(pak->handle, dest, pak->files[i].filelen) != 0)
67 				COM_Error ("I/O errors during copy.");
68 			continue;
69 		}
70 		if (!strcmp (pak->files[i].name, filename))
71 		{
72 			fseek (pak->handle, pak->files[i].filepos, SEEK_SET);
73 			strcpy (dptr, pak->files[i].name);
74 			dest[sizeof(dest) - 1] = '\0';
75 			printf ("%s --> %s\n", pak->files[i].name, dest);
76 			if (Q_WriteFileFromHandle(pak->handle, dest, pak->files[i].filelen) != 0)
77 				COM_Error ("I/O errors during copy.");
78 			break;
79 		}
80 	}
81 	if (filename != NULL && i == pak->numfiles)
82 		fprintf (stderr, "** %s not in %s\n", filename, pak->filename);
83 }
84 
usage(int ret)85 FUNC_NORETURN static void usage (int ret) {
86 	printf ("Usage:  pakx [-outdir <destdir>] <pakfile> [file [file ....]]\n");
87 	printf ("        pakx  -h  to display this help message.\n");
88 	printf ("<destdir> :  Optional. Output directory to extract the files into.\n");
89 	printf ("Without the [file] arguments, all pak file contents get extracted.\n");
90 	printf ("\n");
91 	exit (ret);
92 }
93 
main(int argc,char ** argv)94 int main (int argc, char **argv)
95 {
96 	pack_t 	*pak;
97 	const char	*destdir;
98 	int	i;
99 
100 	if (argc < 2)
101 		usage (1);
102 
103 	for (i = 1; i < argc; i++)
104 	{
105 		if (!strcmp(argv[i], "-h"))
106 			usage (0);
107 	}
108 
109 	if (!strcmp(argv[1], "-outdir"))
110 	{
111 		if (argc < 4)
112 			usage (1);
113 		i = 3;
114 		destdir = argv[2];
115 	}
116 	else
117 	{
118 		i = 1;
119 		destdir = NULL;
120 	}
121 
122 	ValidateByteorder ();
123 
124 	pak = LoadPackFile (argv[i]);
125 	if (!pak)
126 		COM_Error ("Unable to open file %s", argv[i]);
127 	printf ("Opened %s (%i files)\n", pak->filename, pak->numfiles);
128 	if (!pak->numfiles)
129 		COM_Error ("%s has no files.", pak->filename);
130 	if (++i >= argc)
131 		ExtractFile (pak, NULL, destdir);
132 	else
133 	{
134 		for ( ; i < argc; i++)
135 			ExtractFile (pak, argv[i], destdir);
136 	}
137 
138 	return 0;
139 }
140 
141