~ubuntu-branches/ubuntu/trusty/grfcodec/trusty

« back to all changes in this revision

Viewing changes to grfmerge.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthijs Kooijman
  • Date: 2010-08-23 14:45:52 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100823144552-4qggmf9izixsw8li
Tags: 1.0.0+debian1-1
* [30caa6a] Repackaged upstream source, to remove a duplicate file (which
  the lenny version of tar --keep-old-files doesn't like.
* [331d12b] Update watch file to upstream's new versioning scheme.
* [28b6b51] Mangle the +debian suffix in the watch file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/*****************************************\
3
 
*                                         *
4
 
* GRFMerge - A program to integrate a     *
5
 
*            .GRD file generated by       *
6
 
*            GRFDiff into the respective  *
7
 
*                    GRF file.                                    *
8
 
*                                         *
9
 
*                                         *
10
 
* Copyright (C) 2003 by Josef Drexler     *
11
 
*                      <jdrexler@uwo.ca>  *
12
 
*                                         *
13
 
* Permission granted to copy and redist-  *
14
 
* ribute under the terms of the GNU GPL.  *
15
 
* For more info please read the file      *
16
 
* COPYING which should have come with     *
17
 
* this file.                              *
18
 
*                                         *
19
 
\*****************************************/
20
 
 
21
 
#include <stdlib.h>
22
 
#include <stdio.h>
23
 
#include <getopt.h>
24
 
#include <stdarg.h>
25
 
#include <string.h>
26
 
#include <ctype.h>
27
 
#include <errno.h>
28
 
 
29
 
#include "typesize.h"
30
 
#include "version.h"
31
 
 
32
 
static const U32 GRDmagic = 0x67fb49ad;
33
 
#define TEMPFILE "grfmerge.tmp"
34
 
 
35
 
static int alwaysyes = 0;
36
 
static char *grdfile = NULL;
37
 
static long grdofs = 0;
38
 
static int onlyshow = 0, issfx = 0;
39
 
 
40
 
static void usage(void)
41
 
{
42
 
        printf(
43
 
                "\nUsage:\n"
44
 
                "    GRFMerge [options] %s[<GRF-File>]\n"
45
 
                "       Change sprites in the GRF file to the new ones from the GRD file.\n"
46
 
                "       If the GRF file is not specified, GRFMerge will modify the one\n"
47
 
                "       which the GRD file was generated from.\n"
48
 
                "\n"
49
 
                "Options:\n"
50
 
                "       -h  Show this help\n"
51
 
                "       -l  Only show which sprites the GRD file contains, don't integrate them\n"
52
 
                "       -y  Answer 'y' to all questions\n"
53
 
                "\n"
54
 
                "GRFMerge is Copyright (C) 2003 by Josef Drexler <jdrexler@uwo.ca>\n"
55
 
                "It may be freely copied and distributed.\n",
56
 
                issfx?"":"<GRD-File> "
57
 
                );
58
 
 
59
 
        exit(1);
60
 
}
61
 
 
62
 
static int checkisselfextr(const char *exe)
63
 
{
64
 
        FILE *f;
65
 
        char c[3];
66
 
        U8 r, e;
67
 
        U32 magic = 0;
68
 
 
69
 
        f = fopen(exe, "rb");
70
 
        if (!f && errno == ENOENT) {
71
 
                // try appending .exe for Win2k
72
 
                char *altexe = (char*) malloc(strlen(exe)+5);
73
 
                strcpy(altexe, exe);
74
 
                strcat(altexe, ".exe");
75
 
                f = fopen(altexe, "rb");
76
 
                free(altexe);
77
 
        }
78
 
        if (!f) return 0;
79
 
 
80
 
        fread(c, 2, 1, f);
81
 
        if (c[0] != 'M' || c[1] != 'Z')
82
 
                return 0;
83
 
 
84
 
        fseek(f, 0x1c, SEEK_SET);
85
 
        fread(c, 2, 1, f);
86
 
        c[2] = 0;
87
 
 
88
 
        if (!strcmp(c, "JD")) {
89
 
                fread(&r, 1, 1, f);
90
 
                fread(&e, 1, 1, f);
91
 
 
92
 
                grdofs = (long) r * (1L << e);
93
 
                fseek(f, grdofs, SEEK_SET);
94
 
 
95
 
                fread(&magic, 4, 1, f);
96
 
        }
97
 
        fclose(f);
98
 
 
99
 
        return issfx = magic == GRDmagic;
100
 
}
101
 
 
102
 
static void die(const char *text, ...)
103
 
{
104
 
        va_list argptr;
105
 
 
106
 
        va_start(argptr, text);
107
 
        vprintf(text, argptr);
108
 
        va_end(argptr);
109
 
 
110
 
        exit(2);
111
 
}
112
 
 
113
 
static int yesno(const char *txt)
114
 
{
115
 
        char c;
116
 
 
117
 
        printf(" [Y/N] ");
118
 
        if (alwaysyes) {
119
 
                printf("Y\n");
120
 
        } else {
121
 
                c = tolower(getc(stdin));
122
 
 
123
 
                // skip the newline
124
 
                getc(stdin);
125
 
 
126
 
                if (c != 'y') {
127
 
                        printf(txt);
128
 
                        return 0;
129
 
                }
130
 
        }
131
 
        return 1;
132
 
}
133
 
 
134
 
static char *block = NULL;
135
 
#define BLOCKSIZE 8192
136
 
static void copyblock(size_t size, FILE *from, FILE *to)
137
 
{
138
 
        size_t thisblock;
139
 
 
140
 
        while (size > 0) {
141
 
                if (size > BLOCKSIZE)
142
 
                        thisblock = BLOCKSIZE;
143
 
                else
144
 
                        thisblock = size;
145
 
 
146
 
                fread(block, 1, thisblock, from);
147
 
 
148
 
                if (to) fwrite(block, 1, thisblock, to);
149
 
 
150
 
                size -= thisblock;
151
 
        }
152
 
}
153
 
 
154
 
// this function reads a piece of data, and copies it to the other files
155
 
static void copy(void *data, size_t size, size_t n, FILE *from, FILE *to)
156
 
{
157
 
        size_t res;
158
 
 
159
 
        res = fread(data, size, n, from);
160
 
        if (res != n)
161
 
                die("Error while reading, wanted %d, got %d: %s", n, res, strerror(errno));
162
 
 
163
 
        if (to) {
164
 
                res = fwrite(data, size, n, to);
165
 
                if (res != n)
166
 
                        die("Error while writing, wanted %d, wrote %d: %s", n, res, strerror(errno));
167
 
        }
168
 
}
169
 
 
170
 
//
171
 
// Copy the data of a sprite from one file to another
172
 
// this is complicated because for some sprites, the GRF file stores
173
 
// the uncompressed length instead of how many bytes are in the file
174
 
//
175
 
// This code mostly copied from sprites.c, but to keep this program
176
 
// small I didn't link in sprites.c and removed the unnecessary steps
177
 
// from decodesprite (we're not actually interested in the uncompressed data,
178
 
// just the length)
179
 
//
180
 
 
181
 
static U16 copysprite(FILE *from, FILE *to)
182
 
{
183
 
        U8 info, ofs;
184
 
        S8 code;
185
 
        U16 size;
186
 
        size_t reallen;
187
 
 
188
 
#ifdef DEBUG
189
 
        if (from)
190
 
                printf("Copying from pos. %ld\n", ftell(from));
191
 
        if (to)
192
 
                printf("Copying to pos. %ld\n", ftell(to));
193
 
#endif
194
 
 
195
 
        if (feof(from)) return 0;
196
 
 
197
 
        copy(&size, 2, 1, from, to);
198
 
 
199
 
        if (!size) return 0;    // EOF is also indicated by a zero-size sprite
200
 
 
201
 
        copy(&info, 1, 1, from, to);
202
 
 
203
 
        if (info == 0xff) {     // verbatim data
204
 
                copyblock(size, from, to);
205
 
                return 1;
206
 
        }
207
 
 
208
 
        if (info & 2) { // size is compressed size
209
 
                copyblock(size-1, from, to);    // already copied one byte
210
 
                return 1;
211
 
        }
212
 
 
213
 
        // the size given is the uncompressed size, so we need to go through
214
 
        // the uncompression routine until we have enough bytes
215
 
        copyblock(7, from, to);
216
 
        size -= 8;
217
 
        while (size > 0) {
218
 
                copy(&code, 1, 1, from, to);
219
 
 
220
 
                if (code < 0) {
221
 
                        copy(&ofs, 1, 1, from, to);
222
 
                        reallen = -(code >> 3);
223
 
                } else {
224
 
                        reallen = code ? code : 128;
225
 
                        copyblock(reallen, from, to);
226
 
                }
227
 
                if (size < reallen) 
228
 
                        die("\nOops, got too many bytes. How did that happen?\n"
229
 
                        "Size is %d, len is %d at GRF file pos %ld\n",
230
 
                        size, reallen, ftell(from));
231
 
 
232
 
                size -= reallen;
233
 
        }
234
 
        return 1;
235
 
}
236
 
 
237
 
static void skipsprite(FILE *f)
238
 
{
239
 
        copysprite(f, NULL);
240
 
}
241
 
 
242
 
static void showpct(long now, long total, int spriteno, int *pct)
243
 
{
244
 
        int newpct = 100L*now/total;
245
 
 
246
 
        if (newpct == *pct)
247
 
                return;
248
 
 
249
 
        printf("\rSprite%5d  Done:%3d%%  \r", spriteno, newpct);
250
 
        *pct = newpct;
251
 
}
252
 
 
253
 
static int mergeset(FILE *grd, const char *grffile)
254
 
{
255
 
        FILE *grf = NULL, *tmp = NULL;
256
 
        char grflen, *grfname;
257
 
        const char *c;
258
 
        char tempfile[16];
259
 
        U16 version, i, j, numsprites, spriteno, curno;
260
 
        int lastfrom = -2, lastto = lastfrom, lastpct = -1;
261
 
        long grfsize = 0;
262
 
        U32 dummy;
263
 
        int skipped = onlyshow;
264
 
 
265
 
        fread(&version, 2, 1, grd);
266
 
 
267
 
        if (version > 1) die("This is a GRD file version %d, I don't know how to handle that.\n", version);
268
 
 
269
 
        fread(&numsprites, 2, 1, grd);
270
 
        fread(&grflen, 1, 1, grd);
271
 
 
272
 
        grfname = (char*) malloc(grflen + 4);           // +4 for .bak extension (safety margin)
273
 
        if (!grfname) die("Out of memory.\n");
274
 
 
275
 
        fread(grfname, 1, grflen, grd);
276
 
 
277
 
        if (onlyshow) {
278
 
                printf("Generated from: %s.grf\nSprites in file: ", grfname);
279
 
        } else {
280
 
                if (grffile) {
281
 
                        c=strrchr(grffile, '\\');
282
 
                        if (!c) c=strchr(grffile, ':');
283
 
                        if (!c)
284
 
                                c=grffile;
285
 
                        else
286
 
                                c++;
287
 
 
288
 
                        if (strrchr(c, '.'))
289
 
                                j=strrchr(c, '.') - c;
290
 
                        else
291
 
                                j=strlen(c);
292
 
 
293
 
                        if (strnicmp(c, grfname, j)) {
294
 
                                printf("Warning, this GRD file was generated from %s.GRF.\n", grfname);
295
 
                                printf("Are you sure you want to apply it to %s?", grffile);
296
 
                                if (!yesno("Skipping file\n")) {
297
 
                                        for (i=0; i<numsprites; i++) {
298
 
                                                fread(&spriteno, 2, 1, grd);
299
 
                                                skipsprite(grd);
300
 
                                        }
301
 
                                        return 1;
302
 
                                };
303
 
                        }
304
 
                } else {
305
 
                        strcat(grfname, ".grf");
306
 
                        grffile = grfname;
307
 
                }
308
 
 
309
 
                grf = fopen(grffile, "rb");
310
 
                if (!grf) {
311
 
                        printf("Can't open %s: %s. File skipped.\n", grffile, strerror(errno));
312
 
                        skipped = 1;
313
 
                }
314
 
        }
315
 
        if (!skipped) {
316
 
                fseek(grf, 0, SEEK_END);
317
 
                grfsize = ftell(grf);
318
 
                fseek(grf, 0, SEEK_SET);
319
 
 
320
 
                c=strchr(grffile, ':');
321
 
                if (c) {
322
 
                        strncpy(tempfile, grffile, sizeof(tempfile)-1);
323
 
                        i=c-grffile+1;
324
 
                        if (i<sizeof(tempfile))
325
 
                                tempfile[i]=0;
326
 
                } else
327
 
                        tempfile[0] = 0;
328
 
                strncat(tempfile, TEMPFILE, sizeof(tempfile)-strlen(tempfile)-1);
329
 
 
330
 
                tmp = fopen(tempfile, "wb");
331
 
                if (!tmp) die("Can't open %s: %s\n", tempfile, strerror(errno));
332
 
 
333
 
                printf("Writing temporary file %s\n", tempfile);
334
 
        }
335
 
 
336
 
        curno = 0;
337
 
        for (i=0; i<numsprites; i++) {
338
 
                fread(&spriteno, 2, 1, grd);
339
 
 
340
 
                if (skipped) {
341
 
                        if (onlyshow) {
342
 
                                if (spriteno != lastto+1) {
343
 
                                        if (lastfrom != lastto) printf("-%d", lastto);
344
 
                                        if (lastfrom >= 0) printf(", ");
345
 
                                        lastfrom = spriteno;
346
 
                                        printf("%d", lastfrom);
347
 
                                }
348
 
                                lastto = spriteno;
349
 
                        }
350
 
 
351
 
                        skipsprite(grd);
352
 
                } else {
353
 
 
354
 
                        while (++curno <= spriteno) {
355
 
                                copysprite(grf, tmp);
356
 
                                showpct(ftell(grf), grfsize, curno, &lastpct);
357
 
                        }
358
 
 
359
 
                        skipsprite(grf);
360
 
                        copysprite(grd, tmp);
361
 
                        showpct(ftell(grf), grfsize, curno, &lastpct);
362
 
                }
363
 
        }
364
 
 
365
 
        if (onlyshow) {
366
 
                if (lastfrom < 0)
367
 
                        printf("No sprites.");
368
 
                else if (lastfrom != lastto)
369
 
                        printf("-%d", lastto);
370
 
                printf("\n");
371
 
        } else if (!skipped) {
372
 
                // copy remaining sprites, if any
373
 
                for (; copysprite(grf, tmp); )
374
 
                        showpct(ftell(grf), grfsize, ++curno, &lastpct);
375
 
                showpct(grfsize, grfsize, curno, &lastpct);
376
 
 
377
 
                // write the dummy checksum
378
 
                dummy = 0;
379
 
                fwrite(&dummy, 4, 1, tmp);
380
 
        }
381
 
 
382
 
        if (tmp) fclose(tmp);
383
 
        if (grf) fclose(grf);
384
 
 
385
 
        if (!skipped) {
386
 
                char* c;
387
 
 
388
 
                printf("\nDone\n");
389
 
 
390
 
                // rename grf to bak if bak doesn't exist
391
 
                strcpy(block, grffile);
392
 
                c = strrchr(block, '.');
393
 
                if (!c) c = block + strlen(block);
394
 
                strcpy(c, ".bak");
395
 
 
396
 
                tmp = fopen(block, "rb");
397
 
 
398
 
                if (!tmp && (errno == ENOENT)) {
399
 
                        // .bak doesn't exist, rename .grf to .bak
400
 
                        printf("Renaming %s to %s\n", grffile, block);
401
 
                        if (rename(grffile, block)) {
402
 
                                printf("Error while renaming: %s\n", strerror(errno));
403
 
                                printf("Shall I delete it instead?");
404
 
                                if (!yesno("Aborted.\n")) {
405
 
                                        die("");
406
 
                                }
407
 
                                errno = EEXIST;         // go delete it
408
 
                        } else {
409
 
                                errno = ENOENT;         // don't try to delete it
410
 
                        }
411
 
                }
412
 
                if (tmp || (errno != ENOENT)) {
413
 
                        printf("Deleting %s\n", grffile);
414
 
                        if (remove(grffile))
415
 
                                die("Error while deleting: %s\n", strerror(errno));
416
 
                }
417
 
 
418
 
                // rename tmp to grf
419
 
                printf("Renaming %s to %s\n", tempfile, grffile);
420
 
                if (rename(tempfile, grffile))
421
 
                        die("Error while renaming: %s\n", strerror(errno));
422
 
 
423
 
                printf("All done!\n");
424
 
        }
425
 
 
426
 
        free(grfname);
427
 
 
428
 
        return 1;
429
 
}
430
 
 
431
 
static int domerge(int argc, char **argv)
432
 
{
433
 
        FILE *grd;
434
 
        U32 magic;
435
 
        int first = 1;
436
 
 
437
 
        grd = fopen(grdfile, "rb");
438
 
        if (!grd) die("Can't open %s: %s\n", grdfile, strerror(errno));
439
 
 
440
 
        block = (char*) malloc(BLOCKSIZE);
441
 
        if (!block) die("Out of memory.\n");
442
 
 
443
 
        // read all sets of sprites
444
 
        while (1) {
445
 
                if (feof(grd))
446
 
                        break;
447
 
 
448
 
                fseek(grd, grdofs, SEEK_SET);
449
 
                fread(&magic, 4, 1, grd);
450
 
 
451
 
                if (magic != GRDmagic) {
452
 
                        if (first)
453
 
                                die("This is not a GRD file.\n");
454
 
 
455
 
                        break;
456
 
                }
457
 
 
458
 
                first = 0;
459
 
 
460
 
                mergeset(grd, optind < argc ? argv[optind++] : NULL);
461
 
 
462
 
                grdofs = ftell(grd);
463
 
 
464
 
        };
465
 
 
466
 
        if (grd) fclose(grd);
467
 
 
468
 
        free(block);
469
 
 
470
 
        return 1;
471
 
}
472
 
 
473
 
int main(int argc, char **argv)
474
 
{
475
 
        char opt;
476
 
 
477
 
        printf("GRFMerge version " GRFCODECVER " - Copyright (C) 2003 by Josef Drexler\n");
478
 
 
479
 
#ifdef WIN32
480
 
        //  debugint();
481
 
#endif
482
 
 
483
 
        checkisselfextr(argv[0]);
484
 
 
485
 
        while (1) {
486
 
                opt = getopt(argc, argv, "hly");
487
 
 
488
 
                if (opt == (char) EOF)
489
 
                        break;
490
 
 
491
 
                switch (opt) {
492
 
                case 'l':
493
 
                        onlyshow = 1;
494
 
                        break;
495
 
                case 'y':
496
 
                        alwaysyes = 1;
497
 
                        break;
498
 
                default:
499
 
                        usage();
500
 
                }
501
 
        }
502
 
        if (!issfx && (optind < argc) ) // no first arg if we're self-extracting
503
 
                grdfile = argv[optind++];
504
 
 
505
 
        if (grdfile)
506
 
                // see if the GRD file specified is a self-extracting executable
507
 
                // also sets grdofs to skip the .exe code
508
 
                checkisselfextr(grdfile);
509
 
        else {
510
 
                // no GRD file specified; see if we're a self-extracting executable
511
 
                if (issfx)
512
 
                        grdfile = argv[0];
513
 
                else {
514
 
                        printf("No GRD file specified!\n");
515
 
                        exit(2);
516
 
                }
517
 
        }
518
 
 
519
 
        return domerge(argc, argv);
520
 
}