root/src/common/grfio.c @ 6

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