diff options
-rw-r--r-- | src/common/grfio.c | 430 | ||||
-rw-r--r-- | src/common/grfio.h | 88 | ||||
-rw-r--r-- | src/map/map.c | 3 |
3 files changed, 332 insertions, 189 deletions
diff --git a/src/common/grfio.c b/src/common/grfio.c index 4283529d6..0a9708f17 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -35,9 +35,11 @@ #include <sys/stat.h> #include <zlib.h> -//---------------------------- -// file entry table struct -//---------------------------- +/** @file + * Implementation of the GRF I/O interface. + */ + +/// File entry table struct. struct grf_filelist { int srclen; ///< compressed size int srclen_aligned; @@ -50,9 +52,11 @@ struct grf_filelist { int8 gentry; ///< read grf file select }; -#define FILELIST_TYPE_FILE 0x01 // entry is a file -#define FILELIST_TYPE_ENCRYPT_MIXED 0x02 // encryption mode 0 (header DES + periodic DES/shuffle) -#define FILELIST_TYPE_ENCRYPT_HEADER 0x04 // encryption mode 1 (header DES only) +enum grf_filelist_type { + FILELIST_TYPE_FILE = 0x01, ///< entry is a file + FILELIST_TYPE_ENCRYPT_MIXED = 0x02, ///< encryption mode 0 (header DES + periodic DES/shuffle) + FILELIST_TYPE_ENCRYPT_HEADER = 0x04, ///< encryption mode 1 (header DES only) +}; //gentry ... > 0 : data read from a grf file (gentry_table[gentry-1]) //gentry ... 0 : data read from a local file (data directory) @@ -80,23 +84,26 @@ struct grfio_interface grfio_s; struct grfio_interface *grfio; // little endian char array to uint conversion -static unsigned int getlong(unsigned char* p) +static unsigned int getlong(unsigned char *p) { return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); } -static void NibbleSwap(unsigned char* src, int len) +static void NibbleSwap(unsigned char *src, int len) { - while( len > 0 ) - { + while (len > 0) { *src = (*src >> 4) | (*src << 4); ++src; --len; } } -/// Substitutes some specific values for others, leaves rest intact. Obfuscation. -/// NOTE: Operation is symmetric (calling it twice gives back the original input). +/** + * (De)-obfuscates data. + * + * Substitutes some specific values for others, leaves rest intact. + * NOTE: Operation is symmetric (calling it twice gives back the original input). + */ static uint8_t grf_substitution(uint8_t in) { uint8_t out; @@ -157,20 +164,33 @@ static void grf_shuffle_dec(struct des_bit64 *src) *src = out; } -static void grf_decode_header(unsigned char* buf, size_t len) +/** + * Decodes header-encrypted grf data. + * + * @param[in,out] buf Data to decode (in-place). + * @param[in] len Length of the data. + */ +static void grf_decode_header(unsigned char *buf, size_t len) { struct des_bit64 *p = (struct des_bit64 *)buf; size_t nblocks = len / sizeof(struct des_bit64); size_t i; // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) + for (i = 0; i < 20 && i < nblocks; ++i) des->decrypt_block(&p[i]); // the rest is plaintext, done. } -static void grf_decode_full(unsigned char* buf, size_t len, int cycle) +/** + * Decodes fully encrypted grf data + * + * @param[in,out] buf Data to decode (in-place). + * @param[in] len Length of the data. + * @param[in] cycle The current decoding cycle. + */ +static void grf_decode_full(unsigned char *buf, size_t len, int cycle) { struct des_bit64 *p = (struct des_bit64 *)buf; size_t nblocks = len / sizeof(struct des_bit64); @@ -178,7 +198,7 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle) size_t i, j; // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) + for (i = 0; i < 20 && i < nblocks; ++i) des->decrypt_block(&p[i]); // after that only one of every 'dcycle' blocks is des-encrypted @@ -189,17 +209,16 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle) // so decrypt/de-shuffle periodically j = (size_t)-1; // 0, adjusted to fit the ++j step - for( i = 20; i < nblocks; ++i ) - { - if( i % dcycle == 0 ) - {// decrypt block + for (i = 20; i < nblocks; ++i) { + if (i % dcycle == 0) { + // decrypt block des->decrypt_block(&p[i]); continue; } ++j; - if( j % scycle == 0 && j != 0 ) - {// de-shuffle block + if (j % scycle == 0 && j != 0) { + // de-shuffle block grf_shuffle_dec(&p[i]); continue; } @@ -208,22 +227,25 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle) } } -/// Decodes grf data. -/// @param buf data to decode (in-place) -/// @param len length of the data -/// @param entry_type flags associated with the data -/// @param entry_len true (unaligned) length of the data -static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len) +/** + * Decodes grf data. + * + * @param[in,out] buf Data to decode (in-place). + * @param[in] len Length of the data + * @param[in] entry_type Flags associated with the data. + * @param[in] entry_len True (unaligned) length of the data. + */ +static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len) { - if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED ) - {// fully encrypted + if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) { + // fully encrypted int digits; int cycle; int i; // compute number of digits of the entry length digits = 1; - for( i = 10; i <= entry_len; i *= 10 ) + for (i = 10; i <= entry_len; i *= 10) ++digits; // choose size of gap between two encrypted blocks @@ -235,51 +257,47 @@ static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entr : digits + 15; grf_decode_full(buf, len, cycle); - } - else - if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER ) - {// header encrypted + } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) { + // header encrypted grf_decode_header(buf, len); } - else - {// plaintext - ; - } + /* else plaintext */ } -/****************************************************** - *** Zlib Subroutines *** - ******************************************************/ +/* Zlib Subroutines */ -/// zlib crc32 -unsigned long grfio_crc32(const unsigned char* buf, unsigned int len) +/// @copydoc grfio_interface::crc32() +unsigned long grfio_crc32(const unsigned char *buf, unsigned int len) { return crc32(crc32(0L, Z_NULL, 0), buf, len); } -/// zlib uncompress -int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) +/// @copydoc grfio_interface::decode_zip +int grfio_decode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len) { - return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return uncompress(dest, dest_len, source, source_len); } -/// zlib compress -int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) { - if( *destLen == 0 ) /* [Ind/Hercules] */ - *destLen = compressBound(sourceLen); - if( dest == NULL ) { /* [Ind/Hercules] */ - CREATE(dest, unsigned char, *destLen); +/// @copydoc grfio_interface::encode_zip +int grfio_encode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len) +{ + if (*dest_len == 0) /* [Ind/Hercules] */ + *dest_len = compressBound(source_len); + if (dest == NULL) { + /* [Ind/Hercules] */ + CREATE(dest, unsigned char, *dest_len); } - return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return compress(dest, dest_len, source, source_len); } -/*********************************************************** - *** File List Subroutines *** - ***********************************************************/ -// file list hash table +/* File List Subroutines */ + +/// File list hash table int filelist_hash[256]; -// initializes the table that holds the first elements of all hash chains +/** + * Initializes the table that holds the first elements of all hash chains + */ static void hashinit(void) { int i; @@ -287,26 +305,37 @@ static void hashinit(void) filelist_hash[i] = -1; } -// hashes a filename string into a number from {0..255} -static int filehash(const char* fname) +/** + * Hashes a filename string into a number from {0..255} + * + * @param fname The filename to hash. + * @return The hash. + */ +static int grf_filehash(const char *fname) { - unsigned int hash = 0; - while(*fname) { + uint32 hash = 0; + while (*fname != '\0') { hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); fname++; } return hash & 255; } -// finds a grf_filelist entry with the specified file name -static struct grf_filelist *filelist_find(const char *fname) +/** + * Finds a grf_filelist entry with the specified file name + * + * @param fname The file to find. + * @return The file entry. + * @retval NULL if the file wasn't found. + */ +static struct grf_filelist *grfio_filelist_find(const char *fname) { int hash, index; - if (!filelist) + if (filelist == NULL) return NULL; - hash = filelist_hash[filehash(fname)]; + hash = filelist_hash[grf_filehash(fname)]; for (index = hash; index != -1; index = filelist[index].next) if(!strcmpi(filelist[index].fn, fname)) break; @@ -314,17 +343,22 @@ static struct grf_filelist *filelist_find(const char *fname) return (index >= 0) ? &filelist[index] : NULL; } -// returns the original file name -char* grfio_find_file(const char* fname) +/// @copydoc grfio_interface::find_file() +const char *grfio_find_file(const char *fname) { - struct grf_filelist *flist = filelist_find(fname); + struct grf_filelist *flist = grfio_filelist_find(fname); if (flist == NULL) return NULL; return (!flist->fnd ? flist->fn : flist->fnd); } -// adds a grf_filelist entry into the list of loaded files -static struct grf_filelist *filelist_add(struct grf_filelist *entry) +/** + * Adds a grf_filelist entry into the list of loaded files. + * + * @param entry The entry to add. + * @return A pointer to the added entry. + */ +static struct grf_filelist *grfio_filelist_add(struct grf_filelist *entry) { int hash; nullpo_ret(entry); @@ -345,7 +379,7 @@ static struct grf_filelist *filelist_add(struct grf_filelist *entry) memcpy(&filelist[filelist_entrys], entry, sizeof(struct grf_filelist)); - hash = filehash(entry->fn); + hash = grf_filehash(entry->fn); filelist[filelist_entrys].next = filelist_hash[hash]; filelist_hash[hash] = filelist_entrys; @@ -354,22 +388,27 @@ static struct grf_filelist *filelist_add(struct grf_filelist *entry) return &filelist[filelist_entrys - 1]; } -// adds a new grf_filelist entry or overwrites an existing one -static struct grf_filelist *filelist_modify(struct grf_filelist *entry) +/** + * Adds a new grf_filelist entry or overwrites an existing one. + * + * @param entry The entry to add. + * @return A pointer to the added entry. + */ +static struct grf_filelist *grfio_filelist_modify(struct grf_filelist *entry) { - struct grf_filelist *fentry = filelist_find(entry->fn); + struct grf_filelist *fentry = grfio_filelist_find(entry->fn); if (fentry != NULL) { int tmp = fentry->next; memcpy(fentry, entry, sizeof(struct grf_filelist)); fentry->next = tmp; } else { - fentry = filelist_add(entry); + fentry = grfio_filelist_add(entry); } return fentry; } -// shrinks the file list array if too long -static void filelist_compact(void) +/// Shrinks the file list array if too long. +static void grfio_filelist_compact(void) { if (filelist == NULL) return; @@ -380,37 +419,38 @@ static void filelist_compact(void) } } -/*********************************************************** - *** Grfio Subroutines *** - ***********************************************************/ +/* GRF I/O Subroutines */ -/// Combines are resource path with the data folder location to create local resource path. -static void grfio_localpath_create(char* buffer, size_t size, const char* filename) +/** + * Combines a resource path with the data folder location to create local + * resource path. + * + * @param[out] buffer The output buffer. + * @param[in] size The size of the output buffer. + * @param[in] filename Resource path. + */ +static void grfio_localpath_create(char *buffer, size_t size, const char *filename) { - unsigned int i; + int i; size_t len; len = strlen(data_dir); - if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' ) - { + if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\') safesnprintf(buffer, size, "%s%s", data_dir, filename); - } else - { safesnprintf(buffer, size, "%s/%s", data_dir, filename); - } // normalize path - for( i = 0; buffer[i] != '\0'; ++i ) - if( buffer[i] == '\\' ) + for (i = 0; buffer[i] != '\0'; ++i) + if (buffer[i] == '\\') buffer[i] = '/'; } -/// Reads a file into a newly allocated buffer (from grf or data directory). +/// @copydoc grfio_interface::reads() void *grfio_reads(const char *fname, int *size) { - struct grf_filelist *entry = filelist_find(fname); + struct grf_filelist *entry = grfio_filelist_find(fname); if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck char lfname[256]; @@ -429,7 +469,7 @@ void *grfio_reads(const char *fname, int *size) return NULL; } fseek(in,0,SEEK_SET); - buf = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination + buf = aMalloc(declen+1); // +1 for resnametable zero-termination buf[declen] = '\0'; if (fread(buf, 1, declen, in) != (size_t)declen) { ShowError("An error occurred in fread grfio_reads, fname=%s \n",fname); @@ -459,7 +499,7 @@ void *grfio_reads(const char *fname, int *size) if (in != NULL) { int fsize = entry->srclen_aligned; - unsigned char *buf = (unsigned char *)aMalloc(fsize); + unsigned char *buf = aMalloc(fsize); unsigned char *buf2 = NULL; if (fseek(in, entry->srcpos, SEEK_SET) != 0 || fread(buf, 1, fsize, in) != (size_t)fsize) { @@ -470,7 +510,7 @@ void *grfio_reads(const char *fname, int *size) } fclose(in); - buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination + buf2 = aMalloc(entry->declen+1); // +1 for resnametable zero-termination buf2[entry->declen] = '\0'; if (entry->type & FILELIST_TYPE_FILE) { // file @@ -503,35 +543,51 @@ void *grfio_reads(const char *fname, int *size) return NULL; } -/// Decodes encrypted filename from a version 01xx grf index. -static char* decode_filename(unsigned char* buf, int len) +/** + * Decodes encrypted filename from a version 01xx grf index. + * + * @param[in,out] buf The encrypted filename (decrypted in-place). + * @param[in] len The filename length. + * @return A pointer to the decrypted filename. + */ +static char *grfio_decode_filename(unsigned char *buf, int len) { - int lop; - for(lop=0;lop<len;lop+=8) { - NibbleSwap(&buf[lop],8); - des->decrypt(&buf[lop],8); + int i; + for (i = 0; i < len; i += 8) { + NibbleSwap(&buf[i],8); + des->decrypt(&buf[i],8); } return (char*)buf; } -/// Compares file extension against known large file types. -/// @return true if the file should undergo full mode 0 decryption, and true otherwise. -static bool isFullEncrypt(const char* fname) +/** + * Compares file extension against known large file types. + * + * @param fname The file name. + * @return true if the file should undergo full mode 0 decryption, and true otherwise. + */ +static bool grfio_is_full_encrypt(const char *fname) { - const char* ext = strrchr(fname, '.'); - if( ext != NULL ) { - static const char extensions[4][5] = { ".gnd", ".gat", ".act", ".str" }; - size_t i; - for( i = 0; i < ARRAYLENGTH(extensions); ++i ) - if( strcmpi(ext, extensions[i]) == 0 ) + const char *ext = strrchr(fname, '.'); + if (ext != NULL) { + static const char *extensions[] = { ".gnd", ".gat", ".act", ".str" }; + int i; + for (i = 0; i < ARRAYLENGTH(extensions); ++i) + if (strcmpi(ext, extensions[i]) == 0) return false; } return true; } -/// Loads all entries in the specified grf file into the filelist. -/// @param gentry index of the grf file name in the gentry_table +/** + * Loads all entries in the specified grf file into the filelist. + * + * @param grfname Name of the grf file. + * @param gentry Index of the grf file name in the gentry_table. + * @return Error code. + * @retval 0 in case of success. + */ static int grfio_entryread(const char *grfname, int gentry) { long grf_size; @@ -540,12 +596,11 @@ static int grfio_entryread(const char *grfname, int gentry) unsigned char *grf_filelist; FILE *fp = fopen(grfname, "rb"); - if( fp == NULL ) { - ShowWarning("GRF data file not found: '%s'\n",grfname); + if (fp == NULL) { + ShowWarning("GRF data file not found: '%s'\n", grfname); return 1; // 1:not found error - } else { - ShowInfo("GRF data file found: '%s'\n",grfname); } + ShowInfo("GRF data file found: '%s'\n", grfname); fseek(fp,0,SEEK_END); grf_size = ftell(fp); @@ -556,7 +611,7 @@ static int grfio_entryread(const char *grfname, int gentry) fclose(fp); return 2; // 2:file format error } - if (strcmp((const char*)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0) { + if (strcmp((const char*)grf_header, "Master of Magic") != 0 || fseek(fp, getlong(grf_header+0x1e), SEEK_CUR) != 0) { fclose(fp); ShowError("GRF %s read error\n", grfname); return 2; // 2:file format error @@ -566,9 +621,8 @@ static int grfio_entryread(const char *grfname, int gentry) if (grf_version == 0x01) { // ****** Grf version 01xx ****** - long list_size; - list_size = grf_size - ftell(fp); - grf_filelist = (unsigned char *)aMalloc(list_size); + long list_size = grf_size - ftell(fp); + grf_filelist = aMalloc(list_size); if (fread(grf_filelist,1,list_size,fp) != (size_t)list_size) { ShowError("Couldn't read all grf_filelist element of %s \n", grfname); aFree(grf_filelist); @@ -581,11 +635,11 @@ static int grfio_entryread(const char *grfname, int gentry) // Get an entry for (entry = 0, ofs = 0; entry < entrys; ++entry) { - struct grf_filelist aentry; + struct grf_filelist aentry = { 0 }; int ofs2 = ofs+getlong(grf_filelist+ofs)+4; unsigned char type = grf_filelist[ofs2+12]; if (type&FILELIST_TYPE_FILE) { - char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); + char *fname = grfio_decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; if (strlen(fname) > sizeof(aentry.fn) - 1) { @@ -594,7 +648,7 @@ static int grfio_entryread(const char *grfname, int gentry) return 5; // 5: file name too long } - type |= isFullEncrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; + type |= grfio_is_full_encrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; aentry.srclen = srclen; aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; @@ -608,7 +662,7 @@ static int grfio_entryread(const char *grfname, int gentry) #else aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck #endif - filelist_modify(&aentry); + grfio_filelist_modify(&aentry); } ofs = ofs2 + 17; @@ -635,7 +689,7 @@ static int grfio_entryread(const char *grfname, int gentry) return 4; } - rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size + rBuf = aMalloc(rSize); // Get a Read Size if (fread(rBuf,1,rSize,fp) != rSize) { ShowError("An error occurred in fread \n"); fclose(fp); @@ -643,7 +697,7 @@ static int grfio_entryread(const char *grfname, int gentry) return 4; } fclose(fp); - grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size + grf_filelist = aMalloc(eSize); // Get a Extend Size grfio->decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function aFree(rBuf); @@ -677,84 +731,89 @@ static int grfio_entryread(const char *grfname, int gentry) #else aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck #endif - filelist_modify(&aentry); + grfio_filelist_modify(&aentry); } ofs = ofs2 + 17; } aFree(grf_filelist); - } else {// ****** Grf Other version ****** + } else { + // ****** Grf Other version ****** fclose(fp); ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); return 4; } - filelist_compact(); // Unnecessary area release of filelist + grfio_filelist_compact(); // Unnecessary area release of filelist return 0; // 0:no error } -static bool grfio_parse_restable_row(const char* row) +/** + * Parses a Resource file table row. + * + * @param row The row data. + * @return success state. + * @retval true in case of success. + */ +static bool grfio_parse_restable_row(const char *row) { char w1[256], w2[256]; char src[256], dst[256]; char local[256]; - struct grf_filelist *entry; + struct grf_filelist *entry = NULL; if (sscanf(row, "%255[^#\r\n]#%255[^#\r\n]#", w1, w2) != 2) return false; - if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL ) + if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL) return false; // we only need the maps' GAT and RSW files sprintf(src, "data\\%s", w1); sprintf(dst, "data\\%s", w2); - entry = filelist_find(dst); - if( entry != NULL ) - {// alias for GRF resource - struct grf_filelist fentry; - memcpy(&fentry, entry, sizeof(struct grf_filelist)); + entry = grfio_filelist_find(dst); + if (entry != NULL) { + // alias for GRF resource + struct grf_filelist fentry = *entry; safestrncpy(fentry.fn, src, sizeof(fentry.fn)); fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); + grfio_filelist_modify(&fentry); return true; } grfio_localpath_create(local, sizeof(local), dst); - if( exists(local) ) - {// alias for local resource - struct grf_filelist fentry; - memset(&fentry, 0, sizeof(fentry)); + if (exists(local)) { + // alias for local resource + struct grf_filelist fentry = { 0 }; safestrncpy(fentry.fn, src, sizeof(fentry.fn)); fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); + grfio_filelist_modify(&fentry); return true; } return false; } -/// Grfio Resource file check. +/** + * Grfio Resource file check. + */ static void grfio_resourcecheck(void) { char restable[256]; - char *buf; - int size; - FILE* fp; - int i = 0; + char *buf = NULL; + FILE *fp = NULL; + int size = 0, i = 0; // read resnametable from data directory and return if successful grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); fp = fopen(restable, "rb"); - if( fp != NULL ) - { + if (fp != NULL) { char line[256]; - while( fgets(line, sizeof(line), fp) ) - { - if( grfio_parse_restable_row(line) ) + while (fgets(line, sizeof(line), fp)) { + if (grfio_parse_restable_row(line)) ++i; } @@ -765,19 +824,18 @@ static void grfio_resourcecheck(void) // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory buf = grfio->reads("data\\resnametable.txt", &size); - if( buf != NULL ) - { - char *ptr; + if (buf != NULL) { + char *ptr = NULL; buf[size] = '\0'; ptr = buf; - while( ptr - buf < size ) - { - if( grfio_parse_restable_row(ptr) ) + while (ptr - buf < size) { + if (grfio_parse_restable_row(ptr)) ++i; ptr = strchr(ptr, '\n'); - if( ptr == NULL ) break; + if (ptr == NULL) + break; ptr++; } @@ -787,13 +845,19 @@ static void grfio_resourcecheck(void) } } -/// Reads a grf file and adds it to the list. -static int grfio_add(const char* fname) +/** + * Reads a grf file and adds it to the list. + * + * @param fname The file name to read. + * @return Error code. + * @retval 0 in case of success. + */ +static int grfio_add(const char *fname) { if (gentry_entrys >= gentry_maxentry) { #define GENTRY_ADDS 4 // The number increment of gentry_table entries gentry_maxentry += GENTRY_ADDS; - gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); + gentry_table = aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS); #undef GENTRY_ADDS } @@ -803,7 +867,7 @@ static int grfio_add(const char* fname) return grfio_entryread(fname, gentry_entrys - 1); } -/// Finalizes grfio. +/// @copydoc grfio_interface::final() void grfio_final(void) { if (filelist != NULL) { @@ -829,36 +893,33 @@ void grfio_final(void) gentry_entrys = gentry_maxentry = 0; } -/// Initializes grfio. -void grfio_init(const char* fname) +/// @copydoc grfio_interface::init() +void grfio_init(const char *fname) { - FILE* data_conf; + FILE *data_conf; int grf_num = 0; hashinit(); // hash table initialization data_conf = fopen(fname, "r"); - if( data_conf != NULL ) - { + if (data_conf != NULL) { char line[1024]; - while( fgets(line, sizeof(line), data_conf) ) - { + while (fgets(line, sizeof(line), data_conf)) { char w1[1024], w2[1024]; - if( line[0] == '/' && line[1] == '/' ) + if (line[0] == '/' && line[1] == '/') continue; // skip comments if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2) continue; // skip unrecognized lines // Entry table reading - if( strcmp(w1, "grf") == 0 ) // GRF file - { - if( grfio_add(w2) == 0 ) + if (strcmp(w1, "grf") == 0) { + // GRF file + if (grfio_add(w2) == 0) ++grf_num; - } - else if( strcmp(w1,"data_dir") == 0 ) // Data directory - { + } else if (strcmp(w1,"data_dir") == 0) { + // Data directory safestrncpy(data_dir, w2, sizeof(data_dir)); } } @@ -867,16 +928,17 @@ void grfio_init(const char* fname) ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); } - if( grf_num == 0 ) + if (grf_num == 0) ShowInfo("No GRF loaded, using default data directory\n"); // Unnecessary area release of filelist - filelist_compact(); + grfio_filelist_compact(); // Resource check grfio_resourcecheck(); } +/// Interface base initialization. void grfio_defaults(void) { grfio = &grfio_s; @@ -885,6 +947,6 @@ void grfio_defaults(void) grfio->reads = grfio_reads; grfio->find_file = grfio_find_file; grfio->crc32 = grfio_crc32; - grfio->decode_zip = decode_zip; - grfio->encode_zip = encode_zip; + grfio->decode_zip = grfio_decode_zip; + grfio->encode_zip = grfio_encode_zip; } diff --git a/src/common/grfio.h b/src/common/grfio.h index 72afad274..857bc507e 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -23,22 +23,102 @@ #include "common/hercules.h" +/** @file + * GRF I/O library. + */ + +/// The GRF I/O interface. struct grfio_interface { + /** + * Interface initialization. + * + * @param fname Name of the configuration file. + */ void (*init) (const char *fname); + + /// Interface finalization. void (*final) (void); + + /** + * Reads a file into a newly allocated buffer (from grf or data directory). + * + * @param[in] fname Name of the file to read. + * @param[out] size Buffer to return the size of the read file (optional). + * @return The file data. + * @retval NULL in case of error. + */ void *(*reads) (const char *fname, int *size); - char *(*find_file) (const char *fname); + /** + * Finds a file in the grf or data directory + * + * @param fname The file to find. + * @return The original file name. + * @retval NULL if the file wasn't found. + */ + const char *(*find_file) (const char *fname); + + /** + * Calculates a CRC32 hash. + * + * @param buf The data to hash. + * @param len Data length. + * + * @return The CRC32 hash. + */ unsigned long (*crc32) (const unsigned char *buf, unsigned int len); - int (*decode_zip) (void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); - int (*encode_zip) (void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); + + /** + * Decompresses ZIP data. + * + * Decompresses the source buffer into the destination buffer. + * source_len is the byte length of the source buffer. Upon entry, + * dest_len is the total size of the destination buffer, which must be + * large enough to hold the entire uncompressed data. (The size of the + * uncompressed data must have been saved previously by the compressor + * and transmitted to the decompressor by some mechanism outside the + * scope of this compression library.) Upon exit, dest_len is the + * actual size of the uncompressed buffer. + * + * @param[in,out] dest The destination (uncompressed) buffer. + * @param[in,out] dest_len Max length of the destination buffer, returns length of the decompressed data. + * @param[in] source The source (compressed) buffer. + * @param[in] source_len Source data length. + * @return error code. + * @retval Z_OK in case of success. + */ + int (*decode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len); + + /** + * Compresses data to ZIP format. + * + * Compresses the source buffer into the destination buffer. + * source_len is the byte length of the source buffer. Upon entry, + * dest_len is the total size of the destination buffer, which must be + * at least the value returned by compressBound(source_len). Upon + * exit, dest_len is the actual size of the compressed buffer. + * + * @param[in,out] dest The destination (compressed) buffer (if NULL, a new buffer will be created). + * @param[in,out] dest_len Max length of the destination buffer (if 0, it will be calculated). + * @param[in] source The source (uncompressed) buffer. + * @param[in] source_len Source data length. + */ + int (*encode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len); }; +/** + * Reads a file into a newly allocated buffer (from grf or data directory) + * + * @param fn The filename to read. + * + * @see grfio_interface::reads() + * @related grfio_interface + */ #define grfio_read(fn) grfio->reads((fn), NULL) #ifdef HERCULES_CORE void grfio_defaults(void); #endif // HERCULES_CORE -HPShared struct grfio_interface *grfio; +HPShared struct grfio_interface *grfio; ///< Pointer to the grfio interface. #endif /* COMMON_GRFIO_H */ diff --git a/src/map/map.c b/src/map/map.c index 491f6fb59..c5ea7c1f3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3579,7 +3579,8 @@ void map_flags_init(void) { int map_waterheight(char* mapname) { char fn[256]; - char *rsw, *found; + char *rsw = NULL; + const char *found; nullpo_retr(NO_WATER, mapname); //Look up for the rsw |