/*********************************************************************
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <zlib.h>
#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.
}
}