root/src/tool/grfio.c @ 25

Revision 1, 24.5 kB (checked in by jinshiro, 17 years ago)
Line 
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/stat.h>
8#include <ctype.h> // tolower()
9
10#include "grfio.h"
11#include <zlib.h>
12
13
14#ifndef __WIN32
15        #define strcmpi strcasecmp
16#endif
17       
18
19//----------------------------
20//      file entry table struct
21//----------------------------
22typedef struct _FILELIST {
23        int             srclen;                         // compressed size
24        int             srclen_aligned;
25        int             declen;                         // original size
26        int             srcpos;                         // position of entry in grf
27        int             next;                           // index of next filelist entry with same hash (-1: end of entry chain)
28        int             cycle;
29        char    type;
30        char    fn[128-4*5];            // file name
31        char*   fnd;                            // if the file was cloned, contains name of original file
32        char    gentry;                         // read grf file select
33} FILELIST;
34
35//gentry ... > 0  : data read from a grf file (gentry_table[gentry-1])
36//gentry ... 0    : data read from a local file (data directory)
37//gentry ... < 0  : entry "-(gentry)" is marked for a local file check
38//                  - if local file exists, gentry will be set to 0 (thus using the local file)
39//                  - if local file doesn't exist, sign is inverted (thus using the original file inside a grf)
40//                  (NOTE: this case is only used once (during startup) and only if GRFIO_LOCAL is enabled)
41//                  (NOTE: probably meant to be used to override grf contents by files in the data directory)
42//#define GRFIO_LOCAL
43
44// stores info about every loaded file
45FILELIST* filelist              = NULL;
46int filelist_entrys             = 0;
47int filelist_maxentry   = 0;
48
49// stores grf file names
50char** gentry_table             = NULL;
51int gentry_entrys               = 0;
52int gentry_maxentry             = 0;
53
54// the path to the data directory
55char data_dir[1024] = "";
56
57//----------------------------
58//      file list hash table
59//----------------------------
60int filelist_hash[256];
61
62//----------------------------
63//      grf decode data table
64//----------------------------
65static unsigned char BitMaskTable[8] = {
66        0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
67};
68
69static char     BitSwapTable1[64] = {
70        58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12,  4,
71        62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16,  8,
72        57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11,  3,
73        61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15,  7
74};
75static char     BitSwapTable2[64] = {
76        40,  8, 48, 16, 56, 24, 64, 32, 39,  7, 47, 15, 55, 23, 63, 31,
77        38,  6, 46, 14, 54, 22, 62, 30, 37,  5, 45, 13, 53, 21, 61, 29,
78        36,  4, 44, 12, 52, 20, 60, 28, 35,  3, 43, 11, 51, 19, 59, 27,
79        34,  2, 42, 10, 50, 18, 58, 26, 33,  1, 41,  9, 49, 17, 57, 25
80};
81static char     BitSwapTable3[32] = {
82        16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
83     2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
84};
85
86static unsigned char NibbleData[4][64]={
87        {
88                0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47,  0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e,
89                0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba,  0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85,
90                0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21,  0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72,
91                0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec,  0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9,
92        }, {
93                0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95,  0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3,
94                0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec,  0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19,
95                0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06,  0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78,
96                0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b,  0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce,
97        }, {
98                0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2,  0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15,
99                0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae,  0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68,
100                0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c,  0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda,
101                0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97,  0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d,
102        }, {
103                0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78,  0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4,
104                0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb,  0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62,
105                0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87,  0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d,
106                0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0,  0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb,
107        }
108};
109
110// little endian char array to uint conversion
111static unsigned int getlong(unsigned char* p)
112{
113        return (p[0] | p[1] << 0x08 | p[2] << 0x10 | p[3] << 0x18);
114}
115
116/*==========================================
117 *      Grf data decode : Subs
118 *------------------------------------------*/
119static void NibbleSwap(unsigned char* Src, int len)
120{
121        for(;0<len;len--,Src++) {
122                *Src = (*Src>>4) | (*Src<<4);
123        }
124}
125
126static void BitConvert(unsigned char* Src, char* BitSwapTable)
127{
128        int lop,prm;
129        unsigned char tmp[8];
130        memset(tmp,0,8);
131        for(lop=0;lop!=64;lop++) {
132                prm = BitSwapTable[lop]-1;
133                if (Src[(prm >> 3) & 7] & BitMaskTable[prm & 7]) {
134                        tmp[(lop >> 3) & 7] |= BitMaskTable[lop & 7];
135                }
136        }
137        memcpy(Src,tmp,8);
138}
139
140static void BitConvert4(unsigned char* Src)
141{
142        int lop,prm;
143        unsigned char tmp[8];
144        tmp[0] = ((Src[7]<<5) | (Src[4]>>3)) & 0x3f;    // ..0 vutsr
145        tmp[1] = ((Src[4]<<1) | (Src[5]>>7)) & 0x3f;    // ..srqpo n
146        tmp[2] = ((Src[4]<<5) | (Src[5]>>3)) & 0x3f;    // ..o nmlkj
147        tmp[3] = ((Src[5]<<1) | (Src[6]>>7)) & 0x3f;    // ..kjihg f
148        tmp[4] = ((Src[5]<<5) | (Src[6]>>3)) & 0x3f;    // ..g fedcb
149        tmp[5] = ((Src[6]<<1) | (Src[7]>>7)) & 0x3f;    // ..cba98 7
150        tmp[6] = ((Src[6]<<5) | (Src[7]>>3)) & 0x3f;    // ..8 76543
151        tmp[7] = ((Src[7]<<1) | (Src[4]>>7)) & 0x3f;    // ..43210 v
152
153        for(lop=0;lop!=4;lop++) {
154                tmp[lop] = (NibbleData[lop][tmp[lop*2]] & 0xf0)
155                         | (NibbleData[lop][tmp[lop*2+1]] & 0x0f);
156        }
157
158        memset(tmp+4,0,4);
159        for(lop=0;lop!=32;lop++) {
160                prm = BitSwapTable3[lop]-1;
161                if (tmp[prm >> 3] & BitMaskTable[prm & 7]) {
162                        tmp[(lop >> 3) + 4] |= BitMaskTable[lop & 7];
163                }
164        }
165        Src[0] ^= tmp[4];
166        Src[1] ^= tmp[5];
167        Src[2] ^= tmp[6];
168        Src[3] ^= tmp[7];
169}
170
171static void decode_des_etc(unsigned char* buf, size_t len, int type, int cycle)
172{
173        size_t lop,cnt=0;
174        if(cycle<3) cycle=3;
175        else if(cycle<5) cycle++;
176        else if(cycle<7) cycle+=9;
177        else cycle+=15;
178
179        for(lop=0; lop*8<len; lop++, buf+=8)
180        {
181                if(lop<20 || (type==0 && lop%cycle==0)) { // des
182                        BitConvert(buf,BitSwapTable1);
183                        BitConvert4(buf);
184                        BitConvert(buf,BitSwapTable2);
185                } else {
186                        if(cnt==7 && type==0) {
187                                unsigned char a;
188                                unsigned char tmp[8];
189                                memcpy(tmp,buf,8);
190                                cnt=0;
191                                buf[0]=tmp[3];
192                                buf[1]=tmp[4];
193                                buf[2]=tmp[6];
194                                buf[3]=tmp[0];
195                                buf[4]=tmp[1];
196                                buf[5]=tmp[2];
197                                buf[6]=tmp[5];
198                                a=tmp[7];
199                                if(a==0x00) a=0x2b;
200                                else if(a==0x2b) a=0x00;
201                                else if(a==0x01) a=0x68;
202                                else if(a==0x68) a=0x01;
203                                else if(a==0x48) a=0x77;
204                                else if(a==0x77) a=0x48;
205                                else if(a==0x60) a=0xff;
206                                else if(a==0xff) a=0x60;
207                                else if(a==0x6c) a=0x80;
208                                else if(a==0x80) a=0x6c;
209                                else if(a==0xb9) a=0xc0;
210                                else if(a==0xc0) a=0xb9;
211                                else if(a==0xeb) a=0xfe;
212                                else if(a==0xfe) a=0xeb;
213                                buf[7]=a;
214                        }
215                        cnt++;
216                }
217        }
218}
219/*==========================================
220 *      Grf data decode sub : zip
221 *------------------------------------------*/
222int decode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen)
223{
224        z_stream stream;
225        int err;
226
227        stream.next_in = (Bytef*)source;
228        stream.avail_in = (uInt)sourceLen;
229        /* Check for source > 64K on 16-bit machine: */
230        if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
231
232        stream.next_out = (Bytef*) dest;
233        stream.avail_out = (uInt)*destLen;
234        if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
235
236        stream.zalloc = (alloc_func)0;
237        stream.zfree = (free_func)0;
238
239        err = inflateInit(&stream);
240        if (err != Z_OK) return err;
241
242        err = inflate(&stream, Z_FINISH);
243        if (err != Z_STREAM_END) {
244                inflateEnd(&stream);
245                return err == Z_OK ? Z_BUF_ERROR : err;
246        }
247        *destLen = stream.total_out;
248
249        err = inflateEnd(&stream);
250        return err;
251}
252
253int encode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen)
254{
255        z_stream stream;
256        int err;
257        memset(&stream, 0, sizeof(stream));
258        stream.next_in = (Bytef*)source;
259        stream.avail_in = (uInt)sourceLen;
260        /* Check for source > 64K on 16-bit machine: */
261        if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
262
263        stream.next_out = (Bytef*) dest;
264        stream.avail_out = (uInt)*destLen;
265        if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
266
267        stream.zalloc = (alloc_func)0;
268        stream.zfree = (free_func)0;
269
270        err = deflateInit(&stream,Z_DEFAULT_COMPRESSION);
271        if (err != Z_OK) return err;
272
273        err = deflate(&stream, Z_FINISH);
274        if (err != Z_STREAM_END) {
275                inflateEnd(&stream);
276                return err == Z_OK ? Z_BUF_ERROR : err;
277        }
278        *destLen = stream.total_out;
279
280        err = deflateEnd(&stream);
281        return err;
282}
283
284unsigned long grfio_crc32 (const unsigned char* buf, unsigned int len)
285{
286        return crc32(crc32(0L, Z_NULL, 0), buf, len);
287}
288
289/***********************************************************
290 ***                File List Subroutines                ***
291 ***********************************************************/
292
293// initializes the table that holds the first elements of all hash chains
294static void hashinit(void)
295{
296        int i;
297        for (i = 0; i < 256; i++)
298                filelist_hash[i] = -1;
299}
300
301// hashes a filename string into a number from {0..255}
302static int filehash(char* fname)
303{
304        unsigned int hash = 0;
305        while(*fname) {
306                hash = ((hash<<1) + (hash>>7)*9 + (unsigned int)tolower((unsigned char)(*fname)));
307                fname++;
308        }
309        return hash & 255;
310}
311
312// finds a FILELIST entry with the specified file name
313static FILELIST* filelist_find(char* fname)
314{
315        int hash, index;
316
317        if (!filelist)
318                return NULL;
319
320        hash = filelist_hash[filehash(fname)];
321        for (index = hash; index != -1; index = filelist[index].next)
322                if(!strcmpi(filelist[index].fn, fname))
323                        break;
324
325        return (index >= 0) ? &filelist[index] : NULL;
326}
327
328// returns the original file name
329/*
330char* grfio_find_file(char* fname)
331{
332        FILELIST *filelist = filelist_find(fname);
333        if (!filelist) return NULL;
334        return (!filelist->fnd ? filelist->fn : filelist->fnd);
335}
336*/
337
338// adds a FILELIST entry into the list of loaded files
339static FILELIST* filelist_add(FILELIST* entry)
340{
341        int hash;
342
343        #define FILELIST_ADDS   1024    // number increment of file lists `
344
345        if (filelist_entrys >= filelist_maxentry) {
346                filelist = (FILELIST *)realloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST));
347                memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST));
348                filelist_maxentry += FILELIST_ADDS;
349        }
350
351        memcpy (&filelist[filelist_entrys], entry, sizeof(FILELIST));
352
353        hash = filehash(entry->fn);
354        filelist[filelist_entrys].next = filelist_hash[hash];
355        filelist_hash[hash] = filelist_entrys;
356
357        filelist_entrys++;
358
359        return &filelist[filelist_entrys - 1];
360}
361
362// adds a new FILELIST entry or overwrites an existing one
363static FILELIST* filelist_modify(FILELIST* entry)
364{
365        FILELIST* fentry = filelist_find(entry->fn);
366        if (fentry != NULL) {
367                int tmp = fentry->next;
368                memcpy(fentry, entry, sizeof(FILELIST));
369                fentry->next = tmp;
370        } else {
371                fentry = filelist_add(entry);
372        }
373        return fentry;
374}
375
376// shrinks the file list array if too long
377static void filelist_adjust(void)
378{
379        if (filelist == NULL)
380                return;
381       
382        if (filelist_entrys < filelist_maxentry) {
383                filelist = (FILELIST *)realloc(filelist, filelist_entrys * sizeof(FILELIST));
384                filelist_maxentry = filelist_entrys;
385        }
386}
387
388/***********************************************************
389 ***                  Grfio Sobroutines                  ***
390 ***********************************************************/
391
392// returns a file's size
393/*
394int grfio_size(char* fname)
395{
396        FILELIST* entry;
397
398        entry = filelist_find(fname);
399
400        if (entry == NULL || entry->gentry < 0) {       // LocalFileCheck
401                char lfname[256], *p;
402                FILELIST lentry;
403                struct stat st;
404
405                sprintf(lfname, "%s%s", data_dir, fname);
406
407                for (p = &lfname[0]; *p != 0; p++)
408                        if (*p=='\\') *p = '/';
409
410                if (stat(lfname, &st) == 0) {
411                        strncpy(lentry.fn, fname, sizeof(lentry.fn) - 1);
412                        lentry.fnd = NULL;
413                        lentry.declen = st.st_size;
414                        lentry.gentry = 0;      // 0:LocalFile
415                        entry = filelist_modify(&lentry);
416                } else if (entry == NULL) {
417                        printf("%s not found (grfio_size)\n", fname);
418                        return -1;
419                }
420        }
421        return entry->declen;
422}
423*/
424
425// reads a file into a newly allocated buffer (from grf or data directory)
426void* grfio_reads(char* fname, int* size)
427{
428        FILE* in;
429        FILELIST* entry;
430        unsigned char* buf2 = NULL;
431
432        entry = filelist_find(fname);
433
434        if (entry == NULL || entry->gentry <= 0) {      // LocalFileCheck
435                char lfname[256], *p;
436                FILELIST lentry;
437
438                sprintf(lfname, "%s%s", data_dir, fname);
439               
440                for (p = &lfname[0]; *p != 0; p++)
441                        if (*p == '\\') *p = '/';
442
443                in = fopen(lfname, "rb");
444                if (in != NULL) {
445                        if (entry != NULL && entry->gentry == 0) {
446                                lentry.declen = entry->declen;
447                        } else {
448                                fseek(in,0,SEEK_END);
449                                lentry.declen = ftell(in);
450                        }
451                        fseek(in,0,SEEK_SET);
452                        buf2 = (unsigned char *)malloc(lentry.declen + 1024);
453                        fread(buf2, 1, lentry.declen, in);
454                        fclose(in);
455                        strncpy(lentry.fn, fname, sizeof(lentry.fn) - 1);
456                        lentry.fnd = NULL;
457                        lentry.gentry = 0;      // 0:LocalFile
458                        entry = filelist_modify(&lentry);
459                } else {
460                        if (entry != NULL && entry->gentry < 0) {
461                                entry->gentry = -entry->gentry; // local file checked
462                        } else {
463                                printf("%s not found (grfio_reads - local file %s)\n", fname, lfname);
464                                return NULL;
465                        }
466                }
467        }
468        if (entry != NULL && entry->gentry > 0) {       // Archive[GRF] File Read
469                char* grfname = gentry_table[entry->gentry - 1];
470                in = fopen(grfname, "rb");
471                if(in != NULL) {
472                        unsigned char *buf = (unsigned char *)malloc(entry->srclen_aligned + 1024);
473                        fseek(in, entry->srcpos, 0);
474                        fread(buf, 1, entry->srclen_aligned, in);
475                        fclose(in);
476                        buf2 = (unsigned char *)malloc(entry->declen + 1024);
477                        if (entry->type == 1 || entry->type == 3 || entry->type == 5) {
478                                uLongf len;
479                                if (entry->cycle >= 0)
480                                        decode_des_etc(buf, entry->srclen_aligned, entry->cycle == 0, entry->cycle);
481                                len = entry->declen;
482                                decode_zip(buf2, &len, buf, entry->srclen);
483                                if (len != (uLong)entry->declen) {
484                                        printf("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen);
485                                        free(buf);
486                                        free(buf2);
487                                        return NULL;
488                                }
489                        } else {
490                                memcpy(buf2, buf, entry->declen);
491                        }
492                        free(buf);
493                } else {
494                        printf("%s not found (grfio_reads - GRF file %s)\n", fname, grfname);
495                        return NULL;
496                }
497        }
498        if (size != NULL && entry != NULL)
499                *size = entry->declen;
500
501        return buf2;
502}
503
504/*==========================================
505 *      Resource filename decode
506 *------------------------------------------*/
507static char* decode_filename(unsigned char* buf, int len)
508{
509        int lop;
510        for(lop=0;lop<len;lop+=8) {
511                NibbleSwap(&buf[lop],8);
512                BitConvert(&buf[lop],BitSwapTable1);
513                BitConvert4(&buf[lop]);
514                BitConvert(&buf[lop],BitSwapTable2);
515        }
516        return (char*)buf;
517}
518
519// loads all entries in the specified grf file into the filelist
520// gentry - index of the grf file name in the gentry_table
521static int grfio_entryread(char* grfname, int gentry)
522{
523        FILE* fp;
524        long grf_size,list_size;
525        unsigned char grf_header[0x2e];
526        int lop,entry,entrys,ofs,grf_version;
527        char *fname;
528        unsigned char *grf_filelist;
529
530        fp = fopen(grfname, "rb");
531        if (fp == NULL) {
532                printf("GRF data file not found: '%s'\n",grfname);
533                return 1;       // 1:not found error
534        } else
535                printf("GRF data file found: '%s'\n",grfname);
536
537        fseek(fp,0,SEEK_END);
538        grf_size = ftell(fp);
539        fseek(fp,0,SEEK_SET);
540        fread(grf_header,1,0x2e,fp);
541        if (strcmp((const char *) grf_header,"Master of Magic") ||
542                fseek(fp,getlong(grf_header+0x1e),SEEK_CUR))
543        {
544                fclose(fp);
545                printf("GRF %s read error\n", grfname);
546                return 2;       // 2:file format error
547        }
548
549        grf_version = getlong(grf_header+0x2a) >> 8;
550
551        if (grf_version == 0x01) {      //****** Grf version 01xx ******
552                list_size = grf_size - ftell(fp);
553                grf_filelist = (unsigned char *) malloc(list_size);
554                fread(grf_filelist,1,list_size,fp);
555                fclose(fp);
556
557                entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7;
558
559                // Get an entry
560                for (entry = 0,ofs = 0; entry < entrys; entry++) {
561                        int ofs2, srclen, srccount;
562                        unsigned char type;
563                        char* period_ptr;
564                        FILELIST aentry;
565
566                        ofs2 = ofs+getlong(grf_filelist+ofs)+4;
567                        type = grf_filelist[ofs2+12];
568                        if (type != 0) {        // Directory Index ... skip
569                                fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6);
570                                if (strlen(fname) > sizeof(aentry.fn) - 1) {
571                                        printf("GRF file name %s is too long\n", fname);
572                                        free(grf_filelist);
573                                        exit(EXIT_FAILURE);
574                                }
575                                srclen = 0;
576                                if ((period_ptr = strrchr(fname, '.')) != NULL) {
577                                        for(lop = 0; lop < 4; lop++) {
578                                                if (strcmpi(period_ptr, ".gnd\0.gat\0.act\0.str"+lop*5) == 0)
579                                                        break;
580                                        }
581                                        srclen = getlong(grf_filelist+ofs2) - getlong(grf_filelist+ofs2+8) - 715;
582                                        if(lop == 4) {
583                                                for(lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++);
584                                        } else {
585                                                srccount = 0;
586                                        }
587                                } else {
588                                        srccount = 0;
589                                }
590
591                                aentry.srclen         = srclen;
592                                aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579;
593                                aentry.declen         = getlong(grf_filelist+ofs2+8);
594                                aentry.srcpos         = getlong(grf_filelist+ofs2+13)+0x2e;
595                                aentry.cycle          = srccount;
596                                aentry.type           = type;
597                                strncpy(aentry.fn, fname,sizeof(aentry.fn)-1);
598                                aentry.fnd                        = NULL;
599#ifdef  GRFIO_LOCAL
600                                aentry.gentry         = -(gentry+1);    // As Flag for making it a negative number carrying out the first time LocalFileCheck
601#else
602                                aentry.gentry         = gentry+1;               // With no first time LocalFileCheck
603#endif
604                                filelist_modify(&aentry);
605                        }
606                        ofs = ofs2 + 17;
607                }
608                free(grf_filelist);
609
610        } else if (grf_version == 0x02) {       //****** Grf version 02xx ******
611                unsigned char eheader[8];
612                unsigned char *rBuf;
613                uLongf rSize, eSize;
614
615                fread(eheader,1,8,fp);
616                rSize = getlong(eheader);       // Read Size
617                eSize = getlong(eheader+4);     // Extend Size
618
619                if ((long)rSize > grf_size-ftell(fp)) {
620                        fclose(fp);
621                        printf("Illegal data format: GRF compress entry size\n");
622                        return 4;
623                }
624
625                rBuf = (unsigned char *)malloc(rSize);  // Get a Read Size
626                grf_filelist = (unsigned char *)malloc(eSize);  // Get a Extend Size
627                fread(rBuf,1,rSize,fp);
628                fclose(fp);
629                decode_zip(grf_filelist, &eSize, rBuf, rSize);  // Decode function
630                list_size = eSize;
631                free(rBuf);
632
633                entrys = getlong(grf_header+0x26) - 7;
634
635                // Get an entry
636                for(entry = 0, ofs = 0; entry < entrys; entry++) {
637                        int ofs2, srclen, srccount, type;
638                        FILELIST aentry;
639
640                        fname = (char*)(grf_filelist+ofs);
641                        if (strlen(fname) > sizeof(aentry.fn)-1) {
642                                printf("GRF file name %s is too long\n", fname);
643                                free(grf_filelist);
644                                exit(EXIT_FAILURE);
645                        }
646                        ofs2 = ofs + (int)strlen(fname)+1;
647                        type = grf_filelist[ofs2+12];
648                        if (type == 1 || type == 3 || type == 5) {
649                                srclen = getlong(grf_filelist+ofs2);
650                                if (grf_filelist[ofs2+12] == 3) {
651                                        for (lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++);
652                                } else if (grf_filelist[ofs2+12] == 5) {
653                                        srccount = 0;
654                                } else {        // if (grf_filelist[ofs2+12]==1) {
655                                        srccount = -1;
656                                }
657
658                                aentry.srclen         = srclen;
659                                aentry.srclen_aligned = getlong(grf_filelist+ofs2+4);
660                                aentry.declen         = getlong(grf_filelist+ofs2+8);
661                                aentry.srcpos         = getlong(grf_filelist+ofs2+13)+0x2e;
662                                aentry.cycle          = srccount;
663                                aentry.type           = type;
664                                strncpy(aentry.fn,fname,sizeof(aentry.fn)-1);
665                                aentry.fnd                        = NULL;
666#ifdef  GRFIO_LOCAL
667                                aentry.gentry         = -(gentry+1);    // As Flag for making it a negative number carrying out the first time LocalFileCheck
668#else
669                                aentry.gentry         = gentry+1;               // With no first time LocalFileCheck
670#endif
671                                filelist_modify(&aentry);
672                        }
673                        ofs = ofs2 + 17;
674                }
675                free(grf_filelist);
676
677        } else {        //****** Grf Other version ******
678                fclose(fp);
679                printf("GRF version %04x not supported\n",getlong(grf_header+0x2a));
680                return 4;
681        }
682
683        filelist_adjust();      // Unnecessary area release of filelist
684
685        return 0;       // 0:no error
686}
687
688/*==========================================
689 * Grfio : Resource file check
690 *------------------------------------------*/
691static void grfio_resourcecheck(void)
692{
693        char w1[256], w2[256], src[256], dst[256], restable[256], line[256];
694        char *ptr, *buf;
695        FILELIST* entry;
696        int size;
697        FILE* fp;
698
699        // read resnametable from data directory and return if successful
700        sprintf(restable, "%sdata\\resnametable.txt", data_dir);
701        for (ptr = &restable[0]; *ptr != 0; ptr++)
702                if (*ptr == '\\') *ptr = '/';
703
704        fp = fopen(restable, "rb");
705        if (fp) {
706                while(fgets(line, sizeof(line), fp))
707                {
708                        if (sscanf(line, "%[^#]#%[^#]#", w1, w2) == 2 &&
709                                // we only need the maps' GAT and RSW files
710                                (strstr(w2, ".gat") || strstr(w2, ".rsw")))
711                        {
712                                sprintf(src, "data\\%s", w1);
713                                sprintf(dst, "data\\%s", w2);
714                                entry = filelist_find(dst);
715                                // create new entries reusing the original's info
716                                if (entry != NULL) {
717                                        FILELIST fentry;
718                                        memcpy(&fentry, entry, sizeof(FILELIST));
719                                        strncpy(fentry.fn, src, sizeof(fentry.fn) - 1);
720                                        fentry.fnd = strdup(dst);
721                                        filelist_modify(&fentry);
722                                }
723                        }
724                }
725                fclose(fp);
726                return; // we're done here!
727        }
728       
729        // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory
730        buf = (char *)grfio_reads("data\\resnametable.txt", &size);
731        if (buf) {
732                buf[size] = 0;
733
734                ptr = buf;
735                while (ptr - buf < size) {
736                        if (sscanf(ptr, "%[^#]#%[^#]#", w1, w2) == 2 &&
737                                (strstr(w2, ".gat") || strstr(w2, ".rsw")))
738                        {
739                                sprintf(src, "data\\%s", w1);
740                                sprintf(dst, "data\\%s", w2);
741                                entry = filelist_find(dst);
742                                if (entry != NULL) {
743                                        FILELIST fentry;
744                                        memcpy(&fentry, entry, sizeof(FILELIST));
745                                        strncpy(fentry.fn, src, sizeof(fentry.fn) - 1);
746                                        fentry.fnd = strdup(dst);
747                                        filelist_modify(&fentry);
748                                }
749                        }
750                        ptr = strchr(ptr, '\n');        // Next line
751                        if (!ptr) break;
752                        ptr++;
753                }
754                free(buf);
755                return;
756        }
757
758}
759
760// reads a grf file and adds it to the list
761static int grfio_add(char* fname)
762{
763        #define GENTRY_ADDS     4       // The number increment of gentry_table entries
764
765        if (gentry_entrys >= gentry_maxentry) {
766                gentry_maxentry += GENTRY_ADDS;
767                gentry_table = (char**)realloc(gentry_table, gentry_maxentry * sizeof(char*));
768                memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS);
769        }
770
771        gentry_table[gentry_entrys++] = strdup(fname);
772
773        return grfio_entryread(fname, gentry_entrys - 1);
774}
775
776// removes all entries
777void grfio_final(void)
778{
779        if (filelist != NULL) {
780                int i;
781                for (i = 0; i < filelist_entrys; i++)
782                        if (filelist[i].fnd != NULL)
783                                free(filelist[i].fnd);
784
785                free(filelist);
786                filelist = NULL;
787        }
788        filelist_entrys = filelist_maxentry = 0;
789
790        if (gentry_table != NULL) {
791                int i;
792                for (i = 0; i < gentry_entrys; i++)
793                        if (gentry_table[i] != NULL)
794                                free(gentry_table[i]);
795
796                free(gentry_table);
797                gentry_table = NULL;
798        }
799        gentry_entrys = gentry_maxentry = 0;
800}
801
802/*==========================================
803 * Grfio : Initialize
804 *------------------------------------------*/
805void grfio_init(char* fname)
806{
807        FILE* data_conf;
808        char line[1024], w1[1024], w2[1024];
809        int grf_num = 0;
810
811        hashinit();     // hash table initialization
812
813        data_conf = fopen(fname, "r");
814        // It will read, if there is grf-files.txt.
815        if (data_conf) {
816                while(fgets(line, sizeof(line), data_conf))
817                {
818                        if (line[0] == '/' && line[1] == '/')
819                                continue;
820                        if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
821                                continue;
822                        // Entry table reading
823                        if(strcmp(w1, "grf") == 0)      // GRF file
824                                grf_num += (grfio_add(w2) == 0);
825                        else if(strcmp(w1,"data_dir") == 0) {   // Data directory
826                                strcpy(data_dir, w2);
827                                printf("Use data directory %s\n", w2);
828                        }
829                }
830                fclose(data_conf);
831        } // end of reading grf-files.txt
832
833        if (grf_num == 0) {
834                printf("No GRF loaded, using default data directory\n");
835        }
836
837        // Unneccessary area release of filelist
838        filelist_adjust();
839
840        // Resource check
841        grfio_resourcecheck();
842
843        return;
844}
Note: See TracBrowser for help on using the browser.