]> git.draconx.ca Git - liblbx.git/blob - src/lbxtool.c
Update license information.
[liblbx.git] / src / lbxtool.c
1 /* 2ooM: The Master of Orion II Reverse Engineering Project
2  * Simple command-line tool to extract LBX archive files.
3  * Copyright (C) 2006-2008 Nick Bowler
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 #define _GNU_SOURCE
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <fnmatch.h>
25
26 #include "lbx.h"
27
28 static const char *progname;
29 #define errmsg(fmt, ...) (\
30         fprintf(stderr, "%s: " fmt, progname, __VA_ARGS__)\
31 )
32
33 enum {
34         MODE_NONE,
35         MODE_LIST,
36         MODE_EXTRACT,
37 };
38
39 int filematch(char **argv, const char *name)
40 {
41         int rc, i;
42
43         for (i = 0; argv[i]; i++) {
44                 switch(fnmatch(argv[i], name, 0)) {
45                 case 0:
46                         return 0;
47                 case FNM_NOMATCH:
48                         break;
49                 default:
50                         errmsg("error matching glob: %s.\n", argv[i]);
51                         return 1;
52                 }
53         }
54
55         return i ? -1: 0;
56 }
57
58 int list(FILE *f, const char *name, int verbose, char **argv) {
59         LBX *lbx;
60         size_t nfiles;
61         unsigned int i;
62
63         lbx = lbx_fopen(f, name);
64         if (!lbx) {
65                 errmsg("failed to open archive: %s.\n", lbx_strerror());
66                 return EXIT_FAILURE;
67         }
68
69         nfiles = lbx_numfiles(lbx);
70         if (verbose) {
71                 printf("Files in archive: %zu\n", nfiles);
72         }
73
74         for (i = 0; i < nfiles; i++) {
75                 struct lbx_statbuf stat;
76
77                 lbx_stat(lbx, i, &stat);
78
79                 switch (filematch(argv, stat.name)) {
80                 case -1: continue;
81                 case  0: break;
82                 default: goto err;
83                 }
84
85                 printf("%s", stat.name);
86                 if (verbose) {
87                         printf(" size=%zu bytes", stat.size);
88                 }
89
90                 putchar('\n');
91         }
92
93         lbx_close(lbx);
94         return EXIT_SUCCESS;
95 err:
96         lbx_close(lbx);
97         return EXIT_FAILURE;
98 }
99
100 int extract(FILE *f, const char *name, int verbose, char **argv) {
101         LBX *lbx;
102         size_t nfiles;
103         unsigned int i;
104
105         lbx = lbx_fopen(f, name);
106         if (!lbx) {
107                 errmsg("failed to open archive: %s.\n", lbx_strerror());
108                 return EXIT_FAILURE;
109         }
110
111         nfiles = lbx_numfiles(lbx);
112         if (verbose) {
113                 printf("Files in archive: %zu\n", nfiles);
114         }
115
116         for (i = 0; i < nfiles; i++) {
117                 struct lbx_statbuf stat;
118                 size_t rc;
119                 FILE *of;
120                 int j;
121
122                 lbx_stat(lbx, i, &stat);
123
124                 switch (filematch(argv, stat.name)) {
125                 case -1: continue;
126                 case  0: break;
127                 default: goto err;
128                 }
129
130                 of = fopen(stat.name, "wbx");
131                 if (!of) {
132                         errmsg("failed to create output file %s: %m.\n",
133                                                              stat.name);
134                         goto err;
135                 }
136
137                 if (verbose) printf("extracting %s...\n", stat.name);
138                 rc = lbx_extract(lbx, i, of);
139                 if (rc < stat.size) {
140                         if (rc == 0) remove(stat.name);
141                         errmsg("error extracting %s: %s.\n",
142                                stat.name, lbx_strerror());
143                         goto err;
144                 }
145                 if (verbose) printf("wrote %zu bytes.\n", rc);
146         }
147
148         lbx_close(lbx);
149         return EXIT_SUCCESS;
150 err:
151         lbx_close(lbx);
152         return EXIT_FAILURE;
153 }
154
155 int main(int argc, char **argv)
156 {
157         int mode = MODE_NONE, verbose = 0;
158         const char *name = "stdin";
159         FILE *f  = stdin;
160         int opt;
161
162         static const char         *sopts   = "lxf:i:v";
163         static const struct option lopts[] = {
164                 { "list",    0, NULL, 'l' },
165                 { "extract", 0, NULL, 'x' },
166
167                 { "file",    1, NULL, 'f' },
168                 { "index",   1, NULL, 'i' },
169
170                 { "verbose", 0, NULL, 'v' },
171
172                 { 0 }
173         };
174
175         progname = "lbxtool"; /* argv[0]; */
176         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
177                 switch(opt) {
178                 case 'l':
179                         mode = MODE_LIST;
180                         break;
181                 case 'x':
182                         mode = MODE_EXTRACT;
183                         break;
184                 case 'f':
185                         if (strcmp(optarg, "-") == 0)
186                                 break;
187
188                         name = strrchr(optarg, '/');
189                         name = name ? name+1 : optarg;
190
191                         f = fopen(optarg, "rb");
192                         if (!f) {
193                                 errmsg("failed to open file %s: %m\n", optarg);
194                                 return EXIT_FAILURE;
195                         }
196                         break;
197                 case 'i':
198                         /* FIXME: Add index file support. */
199                         break;
200                 case 'v':
201                         verbose = 1;
202                         break;
203                 default:
204                         return EXIT_FAILURE;
205                 }
206         }
207
208         switch (mode) {
209         case MODE_LIST:
210                 return list(f, name, verbose, &argv[optind]);
211         case MODE_EXTRACT:
212                 return extract(f, name, verbose, &argv[optind]);
213         }
214
215         fprintf(stderr, "%s: you must specify a mode.\n", progname);
216         return EXIT_FAILURE;
217 }