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