/********************************************************************* * * Ragnarok Online Emulator : grfio.c -- grf file I/O Module *-------------------------------------------------------------------- * special need library : zlib ********************************************************************* * $Id: grfio.c,v 1.2 2004/09/29 17:31:49 kalaspuff Exp $ * * 2002/12/18... the original edition * 2003/01/23 ... Code correction * 2003/02/01 ... An addition and decryption processing are improved for LocalFile and two or more GRF(s) check processing. * 2003/02/02 ... Even if there is no grf it does not stop -- as -- correction * 2003/02/02... grf reading specification can be added later -- as -- correction (grfio_add function addition) * 2003/02 / 03... at the time of grfio_resourcecheck processing the entry addition processing method -- correction * 2003/02/05... change of the processing in grfio_init * 2003/02/23... a local file check -- GRFIO_LOCAL -- switch (Defoe -- Function Off) * 2003/10/21 ... The data of alpha client was read. * 2003/11/10 ... Ready new grf format. * 2003/11/11 ... version check fix & bug fix */ #include #include #include #include #include #include #include "utils.h" #include "grfio.h" #include "mmo.h" #include "socket.h" #ifdef MEMWATCH #include "memwatch.h" #endif typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; static char data_file[1024] = ""; // "data.grf"; static char sdata_file[1024] = ""; // "sdata.grf"; static char adata_file[1024] = ""; // "adata.grf"; static char data_dir[1024] = ""; // "../"; // accessor to data_file,adata_file,sdata_file char *grfio_setdatafile (const char *str) { strcpy (data_file, str); return data_file; } char *grfio_setadatafile (const char *str) { strcpy (adata_file, str); return adata_file; } char *grfio_setsdatafile (const char *str) { strcpy (sdata_file, str); return sdata_file; } //---------------------------- // file entry table struct //---------------------------- typedef struct { int srclen; // compressed size int srclen_aligned; // int declen; // original size int srcpos; short next; char cycle; char type; char fn[128 - 4 * 5]; // file name char gentry; // read grf file select } FILELIST; //gentry ... 0 : It acquires from a local file. // It acquires from the resource file of 1>=:gentry_table[gentry-1]. // 1<=: Check a local file. // If it is, after re-setting to 0, it acquires from a local file. // If there is nothing, mark reversal will be carried out, and it will re-set, and will acquire from a resource file as well as 1>=. //Since char defines *FILELIST.gentry, the maximum which can be added by grfio_add becomes by 127 pieces. #define GENTRY_LIMIT 127 #define FILELIST_LIMIT 32768 // temporary maximum, and a theory top maximum are 2G. static FILELIST *filelist; static int filelist_entrys; static int filelist_maxentry; static char **gentry_table; static int gentry_entrys; static int gentry_maxentry; //---------------------------- // file list hash table //---------------------------- static int filelist_hash[256]; //---------------------------- // grf decode data table //---------------------------- static unsigned char BitMaskTable[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static char BitSwapTable1[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; static char BitSwapTable2[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; static char BitSwapTable3[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 }; static unsigned char NibbleData[4][64] = { { 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, }, { 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, }, { 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, }, { 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, } }; /*----------------- * long data get */ static unsigned int getlong (unsigned char *p) { return *p + p[1] * 256 + (p[2] + p[3] * 256) * 65536; } /*========================================== * Grf data decode : Subs *------------------------------------------ */ static void NibbleSwap (BYTE * Src, int len) { for (; 0 < len; len--, Src++) { *Src = (*Src >> 4) | (*Src << 4); } } static void BitConvert (BYTE * Src, char *BitSwapTable) { int lop, prm; BYTE tmp[8]; *(DWORD *) tmp = *(DWORD *) (tmp + 4) = 0; for (lop = 0; lop != 64; lop++) { prm = BitSwapTable[lop] - 1; if (Src[(prm >> 3) & 7] & BitMaskTable[prm & 7]) { tmp[(lop >> 3) & 7] |= BitMaskTable[lop & 7]; } } *(DWORD *) Src = *(DWORD *) tmp; *(DWORD *) (Src + 4) = *(DWORD *) (tmp + 4); } static void BitConvert4 (BYTE * Src) { int lop, prm; BYTE tmp[8]; tmp[0] = ((Src[7] << 5) | (Src[4] >> 3)) & 0x3f; // ..0 vutsr tmp[1] = ((Src[4] << 1) | (Src[5] >> 7)) & 0x3f; // ..srqpo n tmp[2] = ((Src[4] << 5) | (Src[5] >> 3)) & 0x3f; // ..o nmlkj tmp[3] = ((Src[5] << 1) | (Src[6] >> 7)) & 0x3f; // ..kjihg f tmp[4] = ((Src[5] << 5) | (Src[6] >> 3)) & 0x3f; // ..g fedcb tmp[5] = ((Src[6] << 1) | (Src[7] >> 7)) & 0x3f; // ..cba98 7 tmp[6] = ((Src[6] << 5) | (Src[7] >> 3)) & 0x3f; // ..8 76543 tmp[7] = ((Src[7] << 1) | (Src[4] >> 7)) & 0x3f; // ..43210 v for (lop = 0; lop != 4; lop++) { tmp[lop] = (NibbleData[lop][tmp[lop * 2]] & 0xf0) | (NibbleData[lop][tmp[lop * 2 + 1]] & 0x0f); } *(DWORD *) (tmp + 4) = 0; for (lop = 0; lop != 32; lop++) { prm = BitSwapTable3[lop] - 1; if (tmp[prm >> 3] & BitMaskTable[prm & 7]) { tmp[(lop >> 3) + 4] |= BitMaskTable[lop & 7]; } } *(DWORD *) Src ^= *(DWORD *) (tmp + 4); } static void decode_des_etc (BYTE * buf, int len, int type, int cycle) { int lop, cnt = 0; if (cycle < 3) cycle = 3; else if (cycle < 5) cycle++; else if (cycle < 7) cycle += 9; else cycle += 15; for (lop = 0; lop * 8 < len; lop++, buf += 8) { if (lop < 20 || (type == 0 && lop % cycle == 0)) { // des BitConvert (buf, BitSwapTable1); BitConvert4 (buf); BitConvert (buf, BitSwapTable2); } else { if (cnt == 7 && type == 0) { int a; BYTE tmp[8]; *(DWORD *) tmp = *(DWORD *) buf; *(DWORD *) (tmp + 4) = *(DWORD *) (buf + 4); cnt = 0; buf[0] = tmp[3]; buf[1] = tmp[4]; buf[2] = tmp[6]; buf[3] = tmp[0]; buf[4] = tmp[1]; buf[5] = tmp[2]; buf[6] = tmp[5]; a = tmp[7]; if (a == 0x00) a = 0x2b; else if (a == 0x2b) a = 0x00; else if (a == 0x01) a = 0x68; else if (a == 0x68) a = 0x01; else if (a == 0x48) a = 0x77; else if (a == 0x77) a = 0x48; else if (a == 0x60) a = 0xff; else if (a == 0xff) a = 0x60; else if (a == 0x6c) a = 0x80; else if (a == 0x80) a = 0x6c; else if (a == 0xb9) a = 0xc0; else if (a == 0xc0) a = 0xb9; else if (a == 0xeb) a = 0xfe; else if (a == 0xfe) a = 0xeb; buf[7] = a; } cnt++; } } } /*========================================== * Grf data decode sub : zip *------------------------------------------ */ static int decode_zip (Bytef * dest, uLongf * destLen, const Bytef * source, uLong sourceLen) { z_stream stream; int err; stream.next_in = (Bytef *) source; stream.avail_in = (uInt) sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong) stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt) * destLen; if ((uLong) stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func) 0; stream.zfree = (free_func) 0; err = inflateInit (&stream); if (err != Z_OK) return err; err = inflate (&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd (&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = inflateEnd (&stream); return err; } /*********************************************************** *** File List Sobroutines *** ***********************************************************/ /*========================================== * File List : Hash make *------------------------------------------ */ static int filehash (unsigned char *fname) { unsigned int hash = 0; while (*fname) { hash = ((hash << 1) + (hash >> 7) * 9 + tolower (*fname)); fname++; } return hash & 255; } /*========================================== * File List : Hash initalize *------------------------------------------ */ static void hashinit (void) { int lop; for (lop = 0; lop < 256; lop++) filelist_hash[lop] = -1; } /*========================================== * File List : File find *------------------------------------------ */ FILELIST *filelist_find (char *fname) { int hash; for (hash = filelist_hash[filehash (fname)]; hash >= 0; hash = filelist[hash].next) { if (strcasecmp (filelist[hash].fn, fname) == 0) break; } return (hash >= 0) ? &filelist[hash] : NULL; } /*========================================== * File List : Filelist add *------------------------------------------ */ #define FILELIST_ADDS 1024 // number increment of file lists ` static FILELIST *filelist_add (FILELIST * entry) { int hash; if (filelist_entrys >= FILELIST_LIMIT) { printf ("filelist limit : filelist_add\n"); exit (1); } if (filelist_entrys >= filelist_maxentry) { FILELIST *new_filelist = (FILELIST *) realloc ((void *) filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof (FILELIST)); if (new_filelist != NULL) { filelist = new_filelist; memset (filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof (FILELIST)); filelist_maxentry += FILELIST_ADDS; } else { printf ("out of memory : filelist_add\n"); exit (1); } } memcpy (&filelist[filelist_entrys], entry, sizeof (FILELIST)); hash = filehash (entry->fn); filelist[filelist_entrys].next = filelist_hash[hash]; filelist_hash[hash] = filelist_entrys; filelist_entrys++; return &filelist[filelist_entrys - 1]; } static FILELIST *filelist_modify (FILELIST * entry) { FILELIST *fentry; if ((fentry = filelist_find (entry->fn)) != NULL) { int tmp = fentry->next; memcpy (fentry, entry, sizeof (FILELIST)); fentry->next = tmp; } else { fentry = filelist_add (entry); } return fentry; } /*========================================== * File List : filelist size adjust *------------------------------------------ */ static void filelist_adjust (void) { if (filelist != NULL) { if (filelist_maxentry > filelist_entrys) { FILELIST *new_filelist = (FILELIST *) realloc ((void *) filelist, filelist_entrys * sizeof (FILELIST)); if (new_filelist != NULL) { filelist = new_filelist; filelist_maxentry = filelist_entrys; } else { printf ("out of memory : filelist\n"); exit (1); } } } } /*********************************************************** *** Grfio Sobroutines *** ***********************************************************/ /*========================================== * Grfio : Resnametable replace *------------------------------------------ */ char *grfio_resnametable (char *fname, char *lfname) { FILE *fp; char *p; char w1[256], w2[256], restable[256], line[512]; sprintf (restable, "%sdata\\resnametable.txt", data_dir); for (p = &restable[0]; *p != 0; p++) if (*p == '\\') *p = '/'; fp = fopen_ (restable, "rb"); if (fp == NULL) { printf ("%s not found\n", restable); exit (1); // 1:not found error } while (fgets (line, 508, fp)) { if ((sscanf (line, "%[^#]#%[^#]#", w1, w2) == 2) && (sscanf (fname, "%*5s%s", lfname) == 1) && (!strcmpi (w1, lfname))) { sprintf (lfname, "data\\%s", w2); fclose_ (fp); return lfname; } } fclose_ (fp); return fname; } /*========================================== * Grfio : Resource file size get *------------------------------------------ */ int grfio_size (char *fname) { FILELIST *entry; entry = filelist_find (fname); if (entry == NULL || entry->gentry < 0) { // LocalFileCheck char lfname[256], rname[256], *p; FILELIST lentry; struct stat st; //printf("%s\t",fname); sprintf (rname, "%s", grfio_resnametable (fname, lfname)); //printf("%s\n",rname); sprintf (lfname, "%s%s", data_dir, rname); //printf("%s\n",lfname); for (p = &lfname[0]; *p != 0; p++) if (*p == '\\') *p = '/'; // * At the time of Unix if (stat (lfname, &st) == 0) { strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); lentry.declen = st.st_size; lentry.gentry = 0; // 0:LocalFile entry = filelist_modify (&lentry); } else if (entry == NULL) { printf ("%s not found\n", fname); //exit(1); return -1; } } return entry->declen; } /*========================================== * Grfio : Resource file read & size get *------------------------------------------ */ void *grfio_reads (char *fname, int *size) { FILE *in = NULL; unsigned char *buf = NULL, *buf2 = NULL; char *gfname; FILELIST *entry; entry = filelist_find (fname); if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck char lfname[256], rname[256], *p; FILELIST lentry; strncpy (lfname, fname, 255); sprintf (rname, "%s", grfio_resnametable (fname, lfname)); sprintf (lfname, "%s%s", data_dir, rname); //printf("%s\n",lfname); for (p = &lfname[0]; *p != 0; p++) if (*p == '\\') *p = '/'; // * At the time of Unix in = fopen_ (lfname, "rb"); if (in != NULL) { if (entry != NULL && entry->gentry == 0) { lentry.declen = entry->declen; } else { fseek (in, 0, 2); // SEEK_END lentry.declen = ftell (in); } fseek (in, 0, 0); // SEEK_SET buf2 = calloc (lentry.declen + 1024, 1); if (buf2 == NULL) { printf ("file read memory allocate error : declen\n"); goto errret; } if (!fread (buf2, 1, lentry.declen, in)) goto errret; fclose_ (in); in = NULL; strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); lentry.gentry = 0; // 0:LocalFile entry = filelist_modify (&lentry); } else { if (entry != NULL && entry->gentry < 0) { entry->gentry = -entry->gentry; // local file checked } else { printf ("%s not found\n", fname); //goto errret; free (buf2); return NULL; } } } if (entry != NULL && entry->gentry > 0) { // Archive[GRF] File Read buf = calloc (entry->srclen_aligned + 1024, 1); if (buf == NULL) { printf ("file read memory allocate error : srclen_aligned\n"); goto errret; } gfname = gentry_table[entry->gentry - 1]; in = fopen_ (gfname, "rb"); if (in == NULL) { printf ("%s not found\n", gfname); //goto errret; free (buf); return NULL; } fseek (in, entry->srcpos, 0); if (!fread (buf, 1, entry->srclen_aligned, in)) goto errret; fclose_ (in); buf2 = calloc (entry->declen + 1024, 1); if (buf2 == NULL) { printf ("file decode memory allocate error\n"); goto errret; } if (entry->type == 1 || entry->type == 3 || entry->type == 5) { uLongf len; if (entry->cycle >= 0) { decode_des_etc (buf, entry->srclen_aligned, entry->cycle == 0, entry->cycle); } len = entry->declen; decode_zip (buf2, &len, buf, entry->srclen); if (len != entry->declen) { printf ("decode_zip size miss match err: %d != %d\n", (int) len, entry->declen); goto errret; } } else { memcpy (buf2, buf, entry->declen); } free (buf); } if (size != NULL && entry != NULL) *size = entry->declen; return buf2; errret: if (buf != NULL) free (buf); if (buf2 != NULL) free (buf2); if (in != NULL) fclose_ (in); exit (1); //return NULL; } /*========================================== * Grfio : Resource file read *------------------------------------------ */ void *grfio_read (char *fname) { return grfio_reads (fname, NULL); } /*========================================== * Resource filename decode *------------------------------------------ */ static unsigned char *decode_filename (unsigned char *buf, int len) { int lop; for (lop = 0; lop < len; lop += 8) { NibbleSwap (&buf[lop], 8); BitConvert (&buf[lop], BitSwapTable1); BitConvert4 (&buf[lop]); BitConvert (&buf[lop], BitSwapTable2); } return buf; } /*========================================== * Grfio : Entry table read *------------------------------------------ */ static int grfio_entryread (char *gfname, int gentry) { FILE *fp; int grf_size, list_size; unsigned char grf_header[0x2e]; int lop, entry, entrys, ofs, grf_version; unsigned char *fname; unsigned char *grf_filelist; fp = fopen_ (gfname, "rb"); if (fp == NULL) { printf ("%s not found\n", gfname); return 1; // 1:not found error } fseek (fp, 0, 2); // SEEK_END grf_size = ftell (fp); fseek (fp, 0, 0); // SEEK_SET if (!fread (grf_header, 1, 0x2e, fp)) return 2; if (strcmp (grf_header, "Master of Magic") || fseek (fp, getlong (grf_header + 0x1e), 1)) { // SEEK_CUR fclose_ (fp); printf ("%s read error\n", gfname); return 2; // 2:file format error } grf_version = getlong (grf_header + 0x2a) >> 8; if (grf_version == 0x01) { //****** Grf version 01xx ****** list_size = grf_size - ftell (fp); grf_filelist = calloc (list_size, 1); if (grf_filelist == NULL) { fclose_ (fp); printf ("out of memory : grf_filelist\n"); return 3; // 3:memory alloc error } if (!fread (grf_filelist, 1, list_size, fp)) return 2; fclose_ (fp); entrys = getlong (grf_header + 0x26) - getlong (grf_header + 0x22) - 7; // Get an entry for (entry = 0, ofs = 0; entry < entrys; entry++) { int ofs2, srclen, srccount, type; char *period_ptr; FILELIST aentry; ofs2 = ofs + getlong (grf_filelist + ofs) + 4; type = grf_filelist[ofs2 + 12]; if (type != 0) { // Directory Index ... skip fname = decode_filename (grf_filelist + ofs + 6, grf_filelist[ofs] - 6); if (strlen (fname) > sizeof (aentry.fn) - 1) { printf ("file name too long : %s\n", fname); free (grf_filelist); exit (1); } srclen = 0; if ((period_ptr = rindex (fname, '.')) != NULL) { for (lop = 0; lop < 4; lop++) { if (strcasecmp (period_ptr, ".gnd\0.gat\0.act\0.str" + lop * 5) == 0) break; } srclen = getlong (grf_filelist + ofs2) - getlong (grf_filelist + ofs2 + 8) - 715; if (lop == 4) { for (lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++); } else { srccount = 0; } } else { srccount = 0; } aentry.srclen = srclen; aentry.srclen_aligned = getlong (grf_filelist + ofs2 + 4) - 37579; aentry.declen = getlong (grf_filelist + ofs2 + 8); aentry.srcpos = getlong (grf_filelist + ofs2 + 13) + 0x2e; aentry.cycle = srccount; aentry.type = type; strncpy (aentry.fn, fname, sizeof (aentry.fn) - 1); #ifdef GRFIO_LOCAL aentry.gentry = -(gentry + 1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else aentry.gentry = gentry + 1; // With no first time LocalFileCheck #endif filelist_modify (&aentry); } ofs = ofs2 + 17; } free (grf_filelist); } else if (grf_version == 0x02) { //****** Grf version 02xx ****** unsigned char eheader[8]; unsigned char *rBuf; uLongf rSize, eSize; if (!fread (eheader, 1, 8, fp)) return 4; rSize = getlong (eheader); // Read Size eSize = getlong (eheader + 4); // Extend Size if (rSize > grf_size - ftell (fp)) { fclose_ (fp); printf ("Illegal data format : grf compress entry size\n"); return 4; } rBuf = calloc (rSize, 1); // Get a Read Size if (rBuf == NULL) { fclose_ (fp); printf ("out of memory : grf compress entry table buffer\n"); return 3; } grf_filelist = calloc (eSize, 1); // Get a Extend Size if (grf_filelist == NULL) { free (rBuf); fclose_ (fp); printf ("out of memory : grf extract entry table buffer\n"); return 3; } if (!fread (rBuf, 1, rSize, fp)) return 4; fclose_ (fp); decode_zip (grf_filelist, &eSize, rBuf, rSize); // Decode function list_size = eSize; free (rBuf); entrys = getlong (grf_header + 0x26) - 7; // Get an entry for (entry = 0, ofs = 0; entry < entrys; entry++) { int ofs2, srclen, srccount, type; FILELIST aentry; fname = grf_filelist + ofs; if (strlen (fname) > sizeof (aentry.fn) - 1) { printf ("grf : file name too long : %s\n", fname); free (grf_filelist); exit (1); } ofs2 = ofs + strlen (grf_filelist + ofs) + 1; type = grf_filelist[ofs2 + 12]; if (type == 1 || type == 3 || type == 5) { srclen = getlong (grf_filelist + ofs2); if (grf_filelist[ofs2 + 12] == 3) { for (lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++); } else if (grf_filelist[ofs2 + 12] == 5) { srccount = 0; } else { // if (grf_filelist[ofs2+12]==1) { srccount = -1; } aentry.srclen = srclen; aentry.srclen_aligned = getlong (grf_filelist + ofs2 + 4); aentry.declen = getlong (grf_filelist + ofs2 + 8); aentry.srcpos = getlong (grf_filelist + ofs2 + 13) + 0x2e; aentry.cycle = srccount; aentry.type = type; strncpy (aentry.fn, fname, sizeof (aentry.fn) - 1); #ifdef GRFIO_LOCAL aentry.gentry = -(gentry + 1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else aentry.gentry = gentry + 1; // With no first time LocalFileCheck #endif filelist_modify (&aentry); } ofs = ofs2 + 17; } free (grf_filelist); } else { //****** Grf Other version ****** fclose_ (fp); printf ("not support grf versions : %04x\n", getlong (grf_header + 0x2a)); return 4; } filelist_adjust (); // Unnecessary area release of filelist return 0; // 0:no error } /*========================================== * Grfio : Resource file check *------------------------------------------ */ static void grfio_resourcecheck () { int size; unsigned char *buf, *ptr; char w1[256], w2[256], src[256], dst[256]; FILELIST *entry; buf = grfio_reads ("data\\resnametable.txt", &size); buf[size] = 0; for (ptr = buf; ptr - buf < size;) { if (sscanf (ptr, "%[^#]#%[^#]#", w1, w2) == 2) { if (strstr (w2, "bmp")) { sprintf (src, "data\\texture\\%s", w1); sprintf (dst, "data\\texture\\%s", w2); } else { sprintf (src, "data\\%s", w1); sprintf (dst, "data\\%s", w2); } entry = filelist_find (dst); if (entry != NULL) { FILELIST fentry; memcpy (&fentry, entry, sizeof (FILELIST)); strncpy (fentry.fn, src, sizeof (fentry.fn) - 1); filelist_modify (&fentry); } else { //printf("file not found in data.grf : %s < %s\n",dst,src); } } ptr = strchr (ptr, '\n'); // Next line if (!ptr) break; ptr++; } free (buf); filelist_adjust (); // Unnecessary area release of filelist } /*========================================== * Grfio : Resource add *------------------------------------------ */ #define GENTRY_ADDS 16 // The number increment of gentry_table entries int grfio_add (char *fname) { int len, result; char *buf; if (gentry_entrys >= GENTRY_LIMIT) { printf ("gentrys limit : grfio_add\n"); exit (1); } printf ("%s file reading...\n", fname); if (gentry_entrys >= gentry_maxentry) { char **new_gentry = (char **) realloc ((void *) gentry_table, (gentry_maxentry + GENTRY_ADDS) * sizeof (char *)); if (new_gentry != NULL) { int lop; gentry_table = new_gentry; gentry_maxentry += GENTRY_ADDS; for (lop = gentry_entrys; lop < gentry_maxentry; lop++) gentry_table[lop] = NULL; } else { printf ("out of memory : grfio_add\n"); exit (1); } } len = strlen (fname); buf = calloc (len + 1, 1); if (buf == NULL) { printf ("out of memory : gentry\n"); exit (1); } strcpy (buf, fname); gentry_table[gentry_entrys++] = buf; result = grfio_entryread (fname, gentry_entrys - 1); if (result == 0) { // Resource check grfio_resourcecheck (); } return result; } /*========================================== * Grfio : Finalize *------------------------------------------ */ void grfio_final (void) { int lop; if (filelist != NULL) free (filelist); filelist = NULL; filelist_entrys = filelist_maxentry = 0; if (gentry_table != NULL) { for (lop = 0; lop < gentry_entrys; lop++) { if (gentry_table[lop] != NULL) { free (gentry_table[lop]); } } free (gentry_table); } gentry_table = NULL; gentry_entrys = gentry_maxentry = 0; } /*========================================== * Grfio : Initialize *------------------------------------------ */ void grfio_init (char *fname) { FILE *data_conf; char line[1024], w1[1024], w2[1024]; int result = 0, result2 = 0, result3 = 0; data_conf = fopen_ (fname, "r"); // It will read, if there is grf-files.txt. if (data_conf) { while (fgets (line, 1020, data_conf)) { if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) { if (strcmp (w1, "data") == 0) strcpy (data_file, w2); else if (strcmp (w1, "sdata") == 0) strcpy (sdata_file, w2); else if (strcmp (w1, "adata") == 0) strcpy (adata_file, w2); else if (strcmp (w1, "data_dir") == 0) strcpy (data_dir, w2); } } fclose_ (data_conf); printf ("read %s done\n", fname); } // end of reading grf-files.txt hashinit (); // hash table initialization filelist = NULL; filelist_entrys = filelist_maxentry = 0; gentry_table = NULL; gentry_entrys = gentry_maxentry = 0; atexit (grfio_final); // End processing definition // Entry table reading if (strcmp (data_file, "") != 0) // If data directive exists in grf-files.txt (i.e. data_file is not equal to "") result = grfio_add (data_file); // Primary data file if (strcmp (sdata_file, "") != 0) // If sdata directive exists in grf-files.txt (i.e. sdata_file is not equal to "") result2 = grfio_add (sdata_file); // Sakray data file if (strcmp (adata_file, "") != 0) // If data directive exists in grf-files.txt (i.e. adata_file is not equal to "") result3 = grfio_add (adata_file); // Alpha version data file if (result != 0 && result2 != 0 && result3 != 0) { printf ("not grf file readed exit!!\n"); exit (1); // It ends, if a resource cannot read one. } }