Mercurial > hg > dmlib
annotate packed.c @ 31:7ad2c6b57932
This ugly trick won't work under MinGW, so disable it there.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 29 Sep 2012 08:42:15 +0300 |
parents | 32250b436bca |
children | 23e03defa759 |
rev | line source |
---|---|
0 | 1 /* |
2 * PACKed - PACKfile EDitor | |
3 * Programmed and designed by Matti 'ccr' Hamalainen | |
4 * (C) Copyright 2011 Tecnic Software productions (TNSP) | |
5 */ | |
6 #include "dmlib.h" | |
7 #include "dmargs.h" | |
8 #include "dmpack.h" | |
9 #include "dmpackutil.h" | |
10 #include <errno.h> | |
11 | |
12 #define SET_MAX_FILES (4096) | |
13 #define SET_DEFAULT_PACK "data.pak" | |
14 | |
15 enum | |
16 { | |
17 CMD_NONE = 0, | |
18 CMD_CREATE, | |
19 CMD_ADD, | |
20 CMD_LIST, | |
21 CMD_EXTRACT | |
22 } DCOMMAND; | |
23 | |
24 enum | |
25 { | |
26 PACK_EXTRACTED = 0x0001, | |
27 }; | |
28 | |
29 int nsrcFilenames = 0; | |
30 char * srcFilenames[SET_MAX_FILES]; | |
31 char * optPackFilename = NULL; | |
32 BOOL optCompress = TRUE; | |
33 int optCommand = CMD_NONE; | |
34 int optDefResFlags = 0; | |
35 | |
36 | |
37 static DMOptArg optList[] = | |
38 { | |
39 { 0, '?', "help", "Show this help", OPT_NONE }, | |
40 { 1, 'p', "pack", "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ }, | |
41 { 2, 'c', "create", "Create and add files to PACK", OPT_NONE }, | |
42 { 3, 'a', "add", "Add files to PACK", OPT_NONE }, | |
43 { 4, 'l', "list", "List files in PACK", OPT_NONE }, | |
44 { 5, 'e', "extract", "Extract files from PACK", OPT_NONE }, | |
45 { 6, 'n', "nocompress", "No compression", OPT_NONE }, | |
46 { 7, 'v', "verbose", "Increase verbosity", OPT_NONE }, | |
47 { 8, 'f', "resflags", "Set default resource flags (-f 0xff)", OPT_ARGREQ }, | |
48 }; | |
49 | |
50 static const int optListN = sizeof(optList) / sizeof(optList[0]); | |
51 | |
52 | |
53 void argShowHelp() | |
54 { | |
55 dmPrintBanner(stdout, dmProgName, "[options] <packfile> [filename[s]]"); | |
56 dmArgsPrintHelp(stdout, optList, optListN); | |
57 fprintf(stdout, | |
58 "\n" | |
59 "Examples:\n" | |
60 "$ %s -p test.pak -l -- list files in test.pak\n" | |
61 "$ %s -a foobar.jpg -- add foobar.jpg in " SET_DEFAULT_PACK "\n" | |
62 "$ %s -x foobar.jpg -- extract foobar.jpg from " SET_DEFAULT_PACK "\n", | |
63 dmProgName, dmProgName, dmProgName); | |
64 } | |
65 | |
66 | |
67 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
68 { | |
69 (void) optArg; | |
70 switch (optN) | |
71 { | |
72 case 0: | |
73 argShowHelp(); | |
74 exit(0); | |
75 break; | |
76 | |
77 case 1: | |
78 optPackFilename = optArg; | |
79 break; | |
80 case 2: | |
81 optCommand = CMD_CREATE; | |
82 break; | |
83 case 3: | |
84 optCommand = CMD_ADD; | |
85 break; | |
86 case 4: | |
87 optCommand = CMD_LIST; | |
88 break; | |
89 case 5: | |
90 optCommand = CMD_EXTRACT; | |
91 break; | |
92 | |
93 case 6: | |
94 optCompress = FALSE; | |
95 break; | |
96 | |
97 case 7: | |
98 dmVerbosity++; | |
99 break; | |
100 | |
101 case 8: | |
102 { | |
103 int i; | |
104 if (!dmGetIntVal(optArg, &i)) | |
105 { | |
106 dmError("Invalid flags value '%s'.\n", optArg); | |
107 return FALSE; | |
108 } | |
109 optDefResFlags = i; | |
110 } | |
111 break; | |
112 | |
113 default: | |
114 dmError("Unknown argument '%s'.\n", currArg); | |
115 return FALSE; | |
116 } | |
117 | |
118 return TRUE; | |
119 } | |
120 | |
121 | |
122 BOOL argHandleFile(char *currArg) | |
123 { | |
124 if (nsrcFilenames < SET_MAX_FILES) | |
125 { | |
126 srcFilenames[nsrcFilenames] = currArg; | |
127 nsrcFilenames++; | |
128 } | |
129 else | |
130 { | |
131 dmError("Maximum number of input files (%i) exceeded!\n", | |
132 SET_MAX_FILES); | |
133 return FALSE; | |
134 } | |
135 return TRUE; | |
136 } | |
137 | |
138 | |
139 /* Compare a string to a pattern. Case-SENSITIVE version. | |
140 * The matching pattern can consist of any normal characters plus | |
141 * wildcards ? and *. "?" matches any character and "*" matches | |
142 * any number of characters. | |
143 */ | |
144 BOOL dm_strmatch(const char *str, const char *pattern) | |
145 { | |
146 BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE; | |
147 const char *tmpPattern = NULL; | |
148 | |
149 // Check given pattern and string | |
150 if (str == NULL || pattern == NULL) | |
151 return FALSE; | |
152 | |
153 // Start comparision | |
154 do { | |
155 didMatch = FALSE; | |
156 switch (*pattern) | |
157 { | |
158 case '?': | |
159 // Any single character matches | |
160 if (*str) | |
161 { | |
162 didMatch = TRUE; | |
163 pattern++; | |
164 str++; | |
165 } | |
166 break; | |
167 | |
168 case '*': | |
169 didMatch = TRUE; | |
170 pattern++; | |
171 if (!*pattern) | |
172 isEnd = TRUE; | |
173 isAnyMode = TRUE; | |
174 tmpPattern = pattern; | |
175 break; | |
176 | |
177 case 0: | |
178 if (isAnyMode) | |
179 { | |
180 if (*str) | |
181 str++; | |
182 else | |
183 isEnd = TRUE; | |
184 } | |
185 else | |
186 { | |
187 if (*str) | |
188 { | |
189 if (tmpPattern) | |
190 { | |
191 isAnyMode = TRUE; | |
192 pattern = tmpPattern; | |
193 } | |
194 else | |
195 didMatch = FALSE; | |
196 } | |
197 else | |
198 isEnd = TRUE; | |
199 } | |
200 break; | |
201 default: | |
202 if (isAnyMode) | |
203 { | |
204 if (*pattern == *str) | |
205 { | |
206 isAnyMode = FALSE; | |
207 didMatch = TRUE; | |
208 } | |
209 else | |
210 { | |
211 if (*str) | |
212 { | |
213 didMatch = TRUE; | |
214 str++; | |
215 } | |
216 } | |
217 } | |
218 else | |
219 { | |
220 if (*pattern == *str) | |
221 { | |
222 didMatch = TRUE; | |
223 if (*pattern) | |
224 pattern++; | |
225 if (*str) | |
226 str++; | |
227 } | |
228 else | |
229 { | |
230 if (tmpPattern) | |
231 { | |
232 didMatch = TRUE; | |
233 isAnyMode = TRUE; | |
234 pattern = tmpPattern; | |
235 } | |
236 } | |
237 } | |
238 | |
239 if (!*str && !*pattern) | |
240 isEnd = TRUE; | |
241 break; | |
242 | |
243 } // switch | |
244 | |
245 } while (didMatch && !isEnd); | |
246 | |
247 return didMatch; | |
248 } | |
249 | |
250 | |
251 int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags) | |
252 { | |
253 DMPackEntry *node; | |
254 int res = dm_pack_add_file(pack, filename, compression, resFlags, &node); | |
255 | |
256 if (res != DMERR_OK) | |
257 { | |
258 dmPrint(1, "%-32s [ERROR:%i]\n", | |
259 filename, res); | |
260 } | |
261 else | |
262 { | |
263 dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=0x%04x]\n", | |
264 filename, node->filename, | |
265 node->size, node->length, node->offset, | |
266 node->resFlags); | |
267 } | |
268 | |
269 return res; | |
270 } | |
271 | |
272 | |
273 int main(int argc, char *argv[]) | |
274 { | |
275 int i, res = 0; | |
276 DMPackFile *pack = NULL; | |
277 | |
31
7ad2c6b57932
This ugly trick won't work under MinGW, so disable it there.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
278 #ifndef __WIN32 |
0 | 279 stderr = stdout; |
31
7ad2c6b57932
This ugly trick won't work under MinGW, so disable it there.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
280 #endif |
0 | 281 |
282 // Parse arguments | |
283 dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL); | |
284 dmVerbosity = 1; | |
285 | |
286 if (!dmArgsProcess(argc, argv, optList, optListN, | |
287 argHandleOpt, argHandleFile, TRUE)) | |
288 exit(1); | |
289 | |
290 // Check PACK filename | |
291 if (optPackFilename == NULL) | |
292 optPackFilename = SET_DEFAULT_PACK; | |
293 | |
294 if (optCommand == CMD_NONE) | |
295 { | |
296 argShowHelp(); | |
297 dmError("Nothing to do.\n"); | |
298 exit(0); | |
299 return 0; | |
300 } | |
301 | |
302 dmMsg(1, "Processing %s ...\n", optPackFilename); | |
303 | |
304 // Execute command | |
305 switch (optCommand) | |
306 { | |
307 case CMD_CREATE: | |
308 case CMD_ADD: | |
309 switch (optCommand) | |
310 { | |
311 case CMD_CREATE: | |
312 dmMsg(1, "Creating new PACK\n"); | |
313 res = dm_pack_create(optPackFilename, &pack); | |
314 break; | |
315 | |
316 case CMD_ADD: | |
317 dmMsg(1, "Opening existing PACK\n"); | |
318 res = dm_pack_open(optPackFilename, &pack, FALSE); | |
319 break; | |
320 } | |
321 | |
322 // Add files into PACK | |
323 if (res == DMERR_OK) | |
324 { | |
325 dmMsg(1, "Adding %d files...\n", nsrcFilenames); | |
326 | |
327 for (i = 0; i < nsrcFilenames; i++) | |
328 { | |
329 // Handle resource definition files | |
330 if (srcFilenames[i][0] == '@') | |
331 { | |
332 } | |
333 else | |
334 { | |
335 dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags); | |
336 } | |
337 } | |
338 | |
339 dmMsg(1, "w=%i\n", dm_pack_write(pack)); | |
340 dmMsg(1, "c=%i\n", dm_pack_close(pack)); | |
341 } | |
342 else | |
343 { | |
344 dmError("Could not open packfile, error #%i: %s\n", res, | |
345 dmErrorStr(res)); | |
346 } | |
347 break; | |
348 | |
349 case CMD_LIST: | |
350 // List files in PACK | |
351 res = dm_pack_open(optPackFilename, &pack, TRUE); | |
352 if (res == DMERR_OK) | |
353 { | |
354 DMPackEntry *node; | |
355 for (i = 0, node = pack->entries; node; i++) | |
356 node = node->next; | |
357 dmMsg(1, "%d files total\n", i); | |
358 | |
359 for (node = pack->entries; node != NULL; node = node->next) | |
360 { | |
361 BOOL match; | |
362 | |
363 // Check for matches | |
364 if (nsrcFilenames > 0) | |
365 { | |
366 match = FALSE; | |
367 for (i = 0; i < nsrcFilenames && !match; i++) | |
368 { | |
369 match = dm_strmatch(node->filename, srcFilenames[i]); | |
370 } | |
371 } | |
372 else | |
373 match = TRUE; | |
374 | |
375 if (match) | |
376 { | |
377 // Print one entry | |
378 dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=0x%04x]\n", | |
379 node->filename, node->size, node->length, | |
380 node->offset, node->resFlags); | |
381 } | |
382 } | |
383 | |
384 dmMsg(1, "c=%i\n", dm_pack_close(pack)); | |
385 } | |
386 else | |
387 dmError("Could not open packfile, error #%i: %s\n", res, | |
388 dmErrorStr(res)); | |
389 break; | |
390 | |
391 case CMD_EXTRACT: | |
392 // Extract files from PACK | |
393 res = dm_pack_open(optPackFilename, &pack, TRUE); | |
394 if (res == DMERR_OK) | |
395 { | |
396 DMPackEntry *node; | |
397 FILE *resFile = fopen(DMRES_RES_FILE, "w"); | |
398 if (resFile == NULL) | |
399 { | |
400 dmError("Could not create resource output file '%s' #%i: %s\n", | |
401 DMRES_RES_FILE, errno, strerror(errno)); | |
402 } | |
403 | |
404 for (node = pack->entries; node != NULL; node = node->next) | |
405 { | |
406 BOOL match; | |
407 | |
408 // Check for matches | |
409 if (nsrcFilenames > 0) | |
410 { | |
411 match = FALSE; | |
412 for (i = 0; (i < nsrcFilenames) && !match; i++) | |
413 { | |
414 match = dm_strmatch(node->filename, srcFilenames[i]); | |
415 } | |
416 } | |
417 else | |
418 match = TRUE; | |
419 | |
420 if (match && (node->privFlags & PACK_EXTRACTED) == 0) | |
421 { | |
422 // Mark as done | |
423 node->privFlags |= PACK_EXTRACTED; | |
424 | |
425 // Print one entry | |
426 dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=0x%04x]\n", | |
427 node->filename, node->size, node->length, | |
428 node->offset, node->resFlags); | |
429 | |
430 dm_pack_extract_file(pack, node); | |
431 | |
432 if (resFile != NULL) | |
433 { | |
434 fprintf(resFile, | |
435 "%s|%04x", node->filename, node->resFlags); | |
436 } | |
437 } | |
438 } | |
439 | |
440 dmMsg(1, "c=%i\n", dm_pack_close(pack)); | |
441 | |
442 if (resFile != NULL) | |
443 fclose(resFile); | |
444 } | |
445 else | |
446 dmError("Could not open packfile, error #%i: %s\n", res, | |
447 dmErrorStr(res)); | |
448 break; | |
449 | |
450 } | |
451 | |
452 return 0; | |
453 } |