From ac349965467725bf4b9690994733cc2b6694cdd4 Mon Sep 17 00:00:00 2001 From: celest Date: Wed, 1 Feb 2006 11:57:21 +0000 Subject: * Fixed an overflow in grfio * Changed resnametable loading behaviour * Increased grfio filelist limit to 1048576 git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5152 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 6 ++ src/common/grfio.c | 299 ++++++++++++++-------------------------------------- src/common/grfio.h | 7 +- 3 files changed, 89 insertions(+), 223 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 7e9ed73a6..ca9108106 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,12 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. EVERYTHING ELSE GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS +2006/02/01 + * Fixed an overflow in grfio causing read problems in Win32 builds [celest] + * Changed resnametable loading behaviour - grfio will load from data directory + first, and then from the highest priority grf only if that fails [celest] + * Increased grfio filelist limit to 1048576 to avoid problems when loading + too many large grfs [celest] 2006/01/31 * Fixed skill_check_cloak to use the current skill level of the cloaking skill and not pc_checkskill() to know if a cloaker away from a wall should diff --git a/src/common/grfio.c b/src/common/grfio.c index a3907a7f2..eef4ea654 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -61,7 +61,7 @@ typedef struct { int declen; // original size int srcpos; short next; - char cycle; + int cycle; char type; char fn[128-4*5]; // file name char gentry; // read grf file select @@ -75,7 +75,7 @@ typedef struct { //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 65536 // temporary maximum, and a theory top maximum are 2G. +#define FILELIST_LIMIT 1048576 // temporary maximum, and a theory top maximum are 2G. static FILELIST *filelist = NULL; static int filelist_entrys = 0; @@ -85,17 +85,6 @@ static char **gentry_table = NULL; static int gentry_entrys = 0; static int gentry_maxentry = 0; -#define RESNAME_LIMIT 1024 -#define RESNAME_ADDS 16 - -typedef struct resname_entry { - char src[64]; - char dst[64]; -} Resname; -static struct resname_entry *localresname = NULL; -static int resname_entrys = 0; -static int resname_maxentrys = 0; - //---------------------------- // file list hash table //---------------------------- @@ -333,78 +322,6 @@ int encode_zip(unsigned char *dest, unsigned long* destLen, const unsigned char* return err; } -/*========================================== -* Decompress from file source to file dest until stream ends or EOF. -* inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be -* allocated for processing, Z_DATA_ERROR if the deflate data is -* invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and -* the version of the library linked do not match, or Z_ERRNO if there -* is an error reading or writing the files. -* -* Version 1.2 9 November 2004 Mark Adler -*------------------------------------------ -*/ -int decode_file (FILE *source, FILE *dest) -{ - int err; - unsigned have; - z_stream strm; - unsigned char in[CHUNK]; - unsigned char out[CHUNK]; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - - err = inflateInit(&strm); - if (err != Z_OK) return 0; //return err; - - /* decompress until deflate stream ends or end of file */ - do { - strm.avail_in = fread(in, 1, CHUNK, source); - if (ferror(source)) { - inflateEnd(&strm); - return 0; - } - if (strm.avail_in == 0) - break; - strm.next_in = in; - - /* run inflate() on input until output buffer not full */ - do { - strm.avail_out = CHUNK; - strm.next_out = out; - err = inflate(&strm, Z_NO_FLUSH); - Assert(err != Z_STREAM_ERROR); /* state not clobbered */ - switch (err) { - case Z_NEED_DICT: - err = Z_DATA_ERROR; /* and fall through */ - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&strm); - //return err; - return 0; - } - have = CHUNK - strm.avail_out; - if (fwrite(out, 1, have, dest) != have || ferror(dest)) { - inflateEnd(&strm); - //return Z_ERRNO; - return 0; - } - } while (strm.avail_out == 0); - Assert(strm.avail_in == 0); /* all input will be used */ - - /* done when inflate() says it's done */ - } while (err != Z_STREAM_END); - - /* clean up and return */ - inflateEnd(&strm); - return err == Z_STREAM_END ? 1 : 0; -} - /* =================================== * Unzips a file. 1: success, 0: error * Adapted from miniunz.c [Celest] @@ -488,7 +405,7 @@ unsigned long grfio_crc32 (const char *buf, unsigned int len) } /*********************************************************** - *** File List Sobroutines *** + *** File List Subroutines *** ***********************************************************/ /*========================================== @@ -520,7 +437,7 @@ static void hashinit(void) * File List : File find *------------------------------------------ */ -FILELIST *filelist_find(char *fname) +static FILELIST *filelist_find(char *fname) { int hash; @@ -546,7 +463,7 @@ static FILELIST* filelist_add(FILELIST *entry) int hash; if (filelist_entrys >= FILELIST_LIMIT) { - ShowFatalError("filelist limit : filelist_add\n"); + ShowFatalError("GRF filelist limit reached (filelist_add)!\n"); exit(1); } @@ -598,78 +515,6 @@ static void filelist_adjust(void) /*********************************************************** *** Grfio Sobroutines *** ***********************************************************/ -/*========================================== - * Grfio : Local Resnametable replace - *------------------------------------------ - */ -static void grfio_resnametable(char *src, char *dest) -{ - int lop; - if (localresname == NULL || - sscanf(src, "%*5s%s", dest) < 1) - { - // if not found copy the unresolved name into buffer - strcpy(dest, src); - return; - } - - for (lop = 0; lop < resname_entrys; lop++) { - if (strcmpi(localresname[lop].src, dest) == 0) { - sprintf(dest, "data\\%s", localresname[lop].dst); - return; - } - } - - return; -} - -/*========================================== - * Grfio : Local Resnametable Initialize - *------------------------------------------ - */ -static void grfio_resnameinit (void) -{ - FILE *fp; - char *p; - // max length per entry is 34 in resnametable - char w1[64], w2[64], restable[256], line[256]; - - sprintf(restable, "%sdata\\resnametable.txt", data_dir); - for (p = &restable[0]; *p != 0; p++) - if (*p == '\\') *p = '/'; - - fp = fopen(restable,"rb"); - if (fp == NULL) { - //ShowError("%s not found (grfio_resnameinit)\n", restable); - return; - } - - while (fgets(line, sizeof(line) - 1, fp)){ - if (sscanf(line, "%[^#]#%[^#]#", w1, w2) != 2) - continue; - // only save up necessary resource files - if (strstr(w1, ".gat") == NULL && - strstr(w1, ".txt") == NULL) - continue; - if (resname_entrys >= RESNAME_LIMIT) - break; - if (resname_entrys >= resname_maxentrys) { - resname_maxentrys += RESNAME_ADDS; - localresname = (Resname*) aRealloc (localresname, resname_maxentrys * sizeof(Resname)); - memset(localresname + (resname_maxentrys - RESNAME_ADDS), '\0', sizeof(Resname) * RESNAME_ADDS); - } - strcpy(localresname[resname_entrys].src, w1); - strcpy(localresname[resname_entrys].dst, w2); - resname_entrys++; - } - fclose(fp); - - // free up unused sections - if (resname_maxentrys > resname_entrys) { - localresname = (Resname*) aRealloc (localresname, resname_entrys * sizeof(Resname)); - resname_maxentrys = resname_entrys; - } -} /*========================================== * Grfio : Resource file size get @@ -682,12 +527,11 @@ int grfio_size(char *fname) entry = filelist_find(fname); if (entry == NULL || entry->gentry < 0) { // LocalFileCheck - char lfname[256], rname[256], *p; + char lfname[256], *p; FILELIST lentry; struct stat st; - grfio_resnametable(fname, rname); - sprintf(lfname, "%s%s", data_dir, rname); + sprintf(lfname, "%s%s", data_dir, fname); for (p = &lfname[0]; *p != 0; p++) if (*p=='\\') *p = '/'; // * At the time of Unix @@ -719,12 +563,10 @@ void* grfio_reads(char *fname, int *size) entry = filelist_find(fname); if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck - char lfname[256], rname[256], *p; + char lfname[256], *p; FILELIST lentry; - // resolve filename into rname - grfio_resnametable(fname, rname); - sprintf(lfname, "%s%s", data_dir, rname); + sprintf(lfname, "%s%s", data_dir, fname); for (p = &lfname[0]; *p != 0; p++) if (*p == '\\') *p = '/'; // * At the time of Unix @@ -789,15 +631,6 @@ void* grfio_reads(char *fname, int *size) return buf2; } -/*========================================== - * Grfio : Resource file read - *------------------------------------------ - */ -void* grfio_read(char *fname) -{ - return grfio_reads(fname, NULL); -} - /*========================================== * Resource filename decode *------------------------------------------ @@ -841,7 +674,7 @@ static int grfio_entryread(char *gfname,int gentry) fseek(fp,getlong(grf_header+0x1e),1)) // SEEK_CUR { fclose(fp); - ShowError("%s read error\n",gfname); + ShowError("GRF %s read error\n",gfname); return 2; // 2:file format error } @@ -871,7 +704,7 @@ static int grfio_entryread(char *gfname,int gentry) if (type != 0) { // Directory Index ... skip fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); if (strlen(fname) > sizeof(aentry.fn) - 1) { - ShowFatalError("file name too long : %s\n",fname); + ShowFatalError("GRF file name %s is too long\n", fname); aFree(grf_filelist); exit(1); } @@ -952,7 +785,7 @@ static int grfio_entryread(char *gfname,int gentry) fname = (char*)(grf_filelist+ofs); if (strlen(fname) > sizeof(aentry.fn)-1) { - ShowFatalError("grf : file name too long : %s\n",fname); + ShowFatalError("GRF file name %s is too long\n", fname); aFree(grf_filelist); exit(1); } @@ -989,7 +822,7 @@ static int grfio_entryread(char *gfname,int gentry) } else { //****** Grf Other version ****** fclose(fp); - ShowError("not support grf versions : %04x\n",getlong(grf_header+0x2a)); + ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); return 4; } @@ -1004,52 +837,85 @@ static int grfio_entryread(char *gfname,int gentry) */ static void grfio_resourcecheck(void) { - int size; - char *buf, *ptr; - char w1[256], w2[256], src[256], dst[256]; + char w1[256], w2[256], src[256], dst[256], restable[256], line[256]; + char *ptr, *buf; FILELIST *entry; + int size, i = 0; + FILE *fp; - buf = (char *)grfio_reads("data\\resnametable.txt", &size); - if (buf == NULL) - return; - buf[size] = 0; + // read resnametable from data directory and return if successful + sprintf(restable, "%sdata\\resnametable.txt", data_dir); + for (ptr = &restable[0]; *ptr != 0; ptr++) + if (*ptr == '\\') *ptr = '/'; - 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 { + fp = fopen(restable,"rb"); + if (fp) { + while (fgets(line, sizeof(line) - 1, fp)) { + if (sscanf(line, "%[^#]#%[^#]#", w1, w2) == 2 && + // we only need the map names and text files + (strstr(w2, ".gat") || strstr(w2, ".txt"))) + { sprintf(src, "data\\%s", w1); sprintf(dst, "data\\%s", w2); + entry = filelist_find(dst); + // create new entries reusing the original's info + if (entry != NULL) { + FILELIST fentry; + memcpy(&fentry, entry, sizeof(FILELIST)); + strncpy(fentry.fn, src, sizeof(fentry.fn) - 1); + filelist_modify(&fentry); + i++; + } } - 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 { - //ShowError("file not found in data.grf : %s < %s\n",dst,src); + } + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); + return; // we're done here! + } + + // read resnametable from loaded GRF's, only if it cannot be + // loaded from the data directory + buf = (char *)grfio_reads("data\\resnametable.txt", &size); + if (buf) { + buf[size] = 0; + ptr = buf; + + while (ptr - buf < size) { + if (sscanf(ptr, "%[^#]#%[^#]#", w1, w2) == 2 && + (strstr(w2, ".gat") || strstr(w2, ".txt"))) + { + 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); + i++; + } } + ptr = strchr(ptr,'\n'); // Next line + if (!ptr) break; + ptr++; } - ptr = strchr(ptr,'\n'); // Next line - if (!ptr) break; - ptr++; + aFree(buf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); + return; } - aFree(buf); - filelist_adjust(); // Unnecessary area release of filelist + + //ShowWarning("GRF: No resnametable found! Panic?\n"); } /*========================================== * Grfio : Resource add *------------------------------------------ */ -#define GENTRY_ADDS 16 // The number increment of gentry_table entries +#define GENTRY_ADDS 4 // The number increment of gentry_table entries -int grfio_add(char *fname) +static int grfio_add(char *fname) { - int len,result; + int len; char *buf; if (gentry_entrys >= GENTRY_LIMIT) { @@ -1067,12 +933,7 @@ int grfio_add(char *fname) strcpy(buf, fname); gentry_table[gentry_entrys++] = buf; - result = grfio_entryread(fname, gentry_entrys - 1); - if (result == 0) - // Resource check - grfio_resourcecheck(); - - return result; + return grfio_entryread(fname, gentry_entrys - 1); } /*========================================== @@ -1095,8 +956,6 @@ void grfio_final(void) } gentry_table = NULL; gentry_entrys = gentry_maxentry = 0; - - if (localresname) aFree(localresname); } /*========================================== @@ -1139,8 +998,10 @@ void grfio_init(char *fname) //exit(1); // It ends, if a resource cannot read one. } - // initialise Resnametable - grfio_resnameinit(); + // Unnecessary area release of filelist + filelist_adjust(); + // Resource check + grfio_resourcecheck(); return; } diff --git a/src/common/grfio.h b/src/common/grfio.h index a7faafc1c..aba9db391 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -6,16 +6,15 @@ void grfio_init(char*); // GRFIO Initialize void grfio_final(void); // GRFIO Finalize -int grfio_add(char*); // GRFIO Resource file add -void* grfio_read(char*); // GRFIO data file read void* grfio_reads(char*,int*); // GRFIO data file read & size get + +#define grfio_read(fn) grfio_reads(fn, NULL) + int grfio_size(char*); // GRFIO data file size get unsigned long grfio_crc32(const char *buf, unsigned int len); int decode_zip(unsigned char *dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen); int encode_zip(unsigned char *dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen); -int decode_file (FILE *source, FILE *dest); - int deflate_file (const char *source, const char *filename); #endif // _GRFIO_H_ -- cgit v1.2.3-60-g2f50