diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/GNUmakefile | 13 | ||||
-rw-r--r-- | src/common/Makefile | 13 | ||||
-rw-r--r-- | src/common/core.c | 152 | ||||
-rw-r--r-- | src/common/core.h | 12 | ||||
-rw-r--r-- | src/common/db.c | 500 | ||||
-rw-r--r-- | src/common/db.h | 47 | ||||
-rw-r--r-- | src/common/grfio.c | 948 | ||||
-rw-r--r-- | src/common/grfio.h | 16 | ||||
-rw-r--r-- | src/common/lock.c | 37 | ||||
-rw-r--r-- | src/common/lock.h | 8 | ||||
-rw-r--r-- | src/common/malloc.c | 44 | ||||
-rw-r--r-- | src/common/malloc.h | 25 | ||||
-rw-r--r-- | src/common/mmo.h | 304 | ||||
-rw-r--r-- | src/common/nullpo.c | 90 | ||||
-rw-r--r-- | src/common/nullpo.h | 222 | ||||
-rw-r--r-- | src/common/socket.c | 439 | ||||
-rw-r--r-- | src/common/socket.h | 96 | ||||
-rw-r--r-- | src/common/timer.c | 312 | ||||
-rw-r--r-- | src/common/timer.h | 45 | ||||
-rw-r--r-- | src/common/utils.c | 108 | ||||
-rw-r--r-- | src/common/utils.h | 33 | ||||
-rw-r--r-- | src/common/version.h | 27 |
22 files changed, 3491 insertions, 0 deletions
diff --git a/src/common/GNUmakefile b/src/common/GNUmakefile new file mode 100644 index 0000000..689ac3b --- /dev/null +++ b/src/common/GNUmakefile @@ -0,0 +1,13 @@ +txt sql all: core.o socket.o timer.o grfio.o db.o lock.o nullpo.o malloc.o
+
+core.o: core.c core.h
+socket.o: socket.c socket.h mmo.h
+timer.o: timer.c timer.h
+grfio.o: grfio.c grfio.h
+db.o: db.c db.h
+lock.o: lock.h
+nullpo.o: nullpo.c nullpo.h
+malloc.o: malloc.c malloc.h
+
+clean:
+ rm -f *.o
diff --git a/src/common/Makefile b/src/common/Makefile new file mode 100644 index 0000000..689ac3b --- /dev/null +++ b/src/common/Makefile @@ -0,0 +1,13 @@ +txt sql all: core.o socket.o timer.o grfio.o db.o lock.o nullpo.o malloc.o
+
+core.o: core.c core.h
+socket.o: socket.c socket.h mmo.h
+timer.o: timer.c timer.h
+grfio.o: grfio.c grfio.h
+db.o: db.c db.h
+lock.o: lock.h
+nullpo.o: nullpo.c nullpo.h
+malloc.o: malloc.c malloc.h
+
+clean:
+ rm -f *.o
diff --git a/src/common/core.c b/src/common/core.c new file mode 100644 index 0000000..62af254 --- /dev/null +++ b/src/common/core.c @@ -0,0 +1,152 @@ +// $Id: core.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +// original : core.c 2003/02/26 18:03:12 Rev 1.7 + +#include <stdio.h> +#include <stdlib.h> +#ifndef LCCWIN32 +#include <unistd.h> +#endif +#include <signal.h> + +#include "core.h" +#include "socket.h" +#include "timer.h" +#include "version.h" + +#ifdef MEMWATCH +#include "memwatch.h" +#endif + +static void (*term_func)(void)=NULL; + +/*====================================== + * CORE : Set function + *-------------------------------------- + */ +void set_termfunc(void (*termfunc)(void)) +{ + term_func = termfunc; +} + +/*====================================== + * CORE : Signal Sub Function + *-------------------------------------- + */ + +static void sig_proc(int sn) +{ + int i; + switch(sn){ + case SIGINT: + case SIGTERM: + if(term_func) + term_func(); + for(i=0;i<fd_max;i++){ + if(!session[i]) + continue; + close(i); + } + exit(0); + break; + } +} + +/*====================================== + * CORE : Display title + *-------------------------------------- + */ + +static void display_title(void) +{ + // for help with the console colors look here: + // http://www.edoceo.com/liberum/?doc=printf-with-color + // some code explanation (used here): + // \033[2J : clear screen and go up/left (0, 0 position) + // \033[K : clear line from actual position to end of the line + // \033[0m : reset color parameter + // \033[1m : use bold for font + printf("\033[2J"); // clear screen and go up/left (0, 0 position in text) + printf("\033[37;44m (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)\033[K\033[0m\n"); // white writing (37) on blue background (44), \033[K clean until end of file + printf("\033[0;44m (\033[1;33m (c)2004 eAthena Development Team presents \033[0;44m)\033[K\033[0m\n"); // yellow writing (33) + printf("\033[0;44m (\033[1m ______ __ __ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m /\\ _ \\/\\ \\__/\\ \\ v%2d.%02d.%02d \033[0;44m)\033[K\033[0m\n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m __\\ \\ \\_\\ \\ \\ ,_\\ \\ \\___ __ ___ __ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m /'__`\\ \\ __ \\ \\ \\/\\ \\ _ `\\ /'__`\\/' _ `\\ /'__`\\ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m /\\ __/\\ \\ \\/\\ \\ \\ \\_\\ \\ \\ \\ \\/\\ __//\\ \\/\\ \\/\\ \\_\\.\\_ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m \\ \\____\\\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\____\\ \\_\\ \\_\\ \\__/.\\_\\ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m \\/____/ \\/_/\\/_/\\/__/ \\/_/\\/_/\\/____/\\/_/\\/_/\\/__/\\/_/ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m _ _ _ _ _ _ _ _ _ _ _ _ _ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m ( e | n | g | l | i | s | h ) ( A | t | h | e | n | a ) \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[0;44m (\033[1m \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \033[0;44m)\033[K\033[0m\n"); // 1: bold char, 0: normal char + printf("\033[37;44m (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)\033[K\033[0m\n\n"); // reset color +} + +// Added by Gabuzomeu +// +// This is an implementation of signal() using sigaction() for portability. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +#ifndef SIGPIPE +#define SIGPIPE SIGINT +#endif + +#ifndef POSIX +#define compat_signal(signo, func) signal(signo, func) +#else +sigfunc *compat_signal(int signo, sigfunc *func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; +#ifdef SA_INTERRUPT + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ +#endif + + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); + + return (oact.sa_handler); +} +#endif + + +/*====================================== + * CORE : MAINROUTINE + *-------------------------------------- + */ + +int runflag = 1; + +int main(int argc,char **argv) +{ + int next; + + Net_Init(); + do_socket(); + + compat_signal(SIGPIPE,SIG_IGN); + compat_signal(SIGTERM,sig_proc); + compat_signal(SIGINT,sig_proc); + + // Signal to create coredumps by system when necessary (crash) + compat_signal(SIGSEGV, SIG_DFL); +#ifndef LCCWIN32 + compat_signal(SIGBUS, SIG_DFL); + compat_signal(SIGTRAP, SIG_DFL); +#endif + compat_signal(SIGILL, SIG_DFL); + + display_title(); + + do_init(argc,argv); + while(runflag){ + next=do_timer(gettick_nocache()); + do_sendrecv(next); + do_parsepacket(); + } + return 0; +} diff --git a/src/common/core.h b/src/common/core.h new file mode 100644 index 0000000..bc2be02 --- /dev/null +++ b/src/common/core.h @@ -0,0 +1,12 @@ +// original : core.h 2003/03/14 11:55:25 Rev 1.4 + +#ifndef _CORE_H_ +#define _CORE_H_ + +extern int runflag; + +int do_init(int,char**); + +void set_termfunc(void (*termfunc)(void)); + +#endif // _CORE_H_ diff --git a/src/common/db.c b/src/common/db.c new file mode 100644 index 0000000..a2dc695 --- /dev/null +++ b/src/common/db.c @@ -0,0 +1,500 @@ +// $Id: db.c,v 1.2 2004/09/23 14:43:06 MouseJstr Exp $ +// #define MALLOC_DBN +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "db.h" +#include "utils.h" + +#ifdef MEMWATCH +#include "memwatch.h" +#endif + +#define ROOT_SIZE 4096 +#ifdef MALLOC_DBN +static struct dbn *dbn_root[512], *dbn_free; +static int dbn_root_rest=0,dbn_root_num=0; + +static void * malloc_dbn(void) +{ + struct dbn* ret; + + if(dbn_free==NULL){ + if(dbn_root_rest<=0){ + CREATE(dbn_root[dbn_root_num], struct dbn, ROOT_SIZE); + + dbn_root_rest=ROOT_SIZE; + dbn_root_num++; + } + return &(dbn_root[dbn_root_num-1][--dbn_root_rest]); + } + ret=dbn_free; + dbn_free = dbn_free->parent; + return ret; +} + +static void free_dbn(struct dbn* add_dbn) +{ + add_dbn->parent = dbn_free; + dbn_free = add_dbn; +} +#endif + +static int strdb_cmp(struct dbt* table,void* a,void* b) +{ + if(table->maxlen) + return strncmp(a,b,table->maxlen); + return strcmp(a,b); +} + +static unsigned int strdb_hash(struct dbt* table,void* a) +{ + int i; + unsigned int h; + unsigned char *p=a; + + i=table->maxlen; + if(i==0) i=0x7fffffff; + for(h=0;*p && --i>=0;){ + h=(h*33 + *p++) ^ (h>>24); + } + return h; +} + +struct dbt* strdb_init(int maxlen) +{ + int i; + struct dbt* table; + + CREATE(table, struct dbt, 1); + + table->cmp=strdb_cmp; + table->hash=strdb_hash; + table->maxlen=maxlen; + for(i=0;i<HASH_SIZE;i++) + table->ht[i]=NULL; + return table; +} + +static int numdb_cmp(struct dbt* table,void* a,void* b) +{ + int ia,ib; + + ia=(int)a; + ib=(int)b; + + if((ia^ib) & 0x80000000) + return ia<0 ? -1 : 1; + + return ia-ib; +} + +static unsigned int numdb_hash(struct dbt* table,void* a) +{ + return (unsigned int)a; +} + +struct dbt* numdb_init(void) +{ + int i; + struct dbt* table; + + CREATE(table, struct dbt, 1); + + table->cmp=numdb_cmp; + table->hash=numdb_hash; + table->maxlen=sizeof(int); + for(i=0;i<HASH_SIZE;i++) + table->ht[i]=NULL; + return table; +} + +void* db_search(struct dbt *table,void* key) +{ + struct dbn *p; + + for(p=table->ht[table->hash(table,key) % HASH_SIZE];p;){ + int c=table->cmp(table,key,p->key); + if(c==0) + return p->data; + if(c<0) + p=p->left; + else + p=p->right; + } + return NULL; +} + +void * db_search2(struct dbt *table, const char *key) +{ + int i,sp; + struct dbn *p,*pn,*stack[64]; + int slen = strlen(key); + + for(i=0;i<HASH_SIZE;i++){ + if((p=table->ht[i])==NULL) + continue; + sp=0; + while(1){ + if (strncasecmp(key, p->key, slen) == 0) + return p->data; + if((pn=p->left)!=NULL){ + if(p->right){ + stack[sp++]=p->right; + } + p=pn; + } else { + if(p->right){ + p=p->right; + } else { + if(sp==0) + break; + p=stack[--sp]; + } + } + } + } + return 0; +} + +static void db_rotate_left(struct dbn *p,struct dbn **root) +{ + struct dbn * y = p->right; + p->right = y->left; + if (y->left !=0) + y->left->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->left) + p->parent->left = y; + else + p->parent->right = y; + y->left = p; + p->parent = y; +} + +static void db_rotate_right(struct dbn *p,struct dbn **root) +{ + struct dbn * y = p->left; + p->left = y->right; + if (y->right != 0) + y->right->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->right) + p->parent->right = y; + else + p->parent->left = y; + y->right = p; + p->parent = y; +} + +static void db_rebalance(struct dbn *p,struct dbn **root) +{ + p->color = RED; + while(p!=*root && p->parent->color==RED){ // rootは必ず黒で親は赤いので親の親は必ず存在する + if (p->parent == p->parent->parent->left) { + struct dbn *y = p->parent->parent->right; + if (y && y->color == RED) { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } else { + if (p == p->parent->right) { + p = p->parent; + db_rotate_left(p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_right(p->parent->parent, root); + } + } else { + struct dbn* y = p->parent->parent->left; + if (y && y->color == RED) { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } else { + if (p == p->parent->left) { + p = p->parent; + db_rotate_right(p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_left(p->parent->parent, root); + } + } + } + (*root)->color=BLACK; +} + +static void db_rebalance_erase(struct dbn *z,struct dbn **root) +{ + struct dbn *y = z, *x = NULL, *x_parent = NULL; + + if (y->left == NULL) + x = y->right; + else if (y->right == NULL) + x = y->left; + else { + y = y->right; + while (y->left != NULL) + y = y->left; + x = y->right; + } + if (y != z) { // 左右が両方埋まっていた時 yをzの位置に持ってきてzを浮かせる + z->left->parent = y; + y->left = z->left; + if (y != z->right) { + x_parent = y->parent; + if (x) x->parent = y->parent; + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } else + x_parent = y; + if (*root == z) + *root = y; + else if (z->parent->left == z) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + { int tmp=y->color; y->color=z->color; z->color=tmp; } + y = z; + } else { // どちらか空いていた場合 xをzの位置に持ってきてzを浮かせる + x_parent = y->parent; + if (x) x->parent = y->parent; + if (*root == z) + *root = x; + else if (z->parent->left == z) + z->parent->left = x; + else + z->parent->right = x; + } + // ここまで色の移動の除いて通常の2分木と同じ + if (y->color != RED) { // 赤が消える分には影響無し + while (x != *root && (x == NULL || x->color == BLACK)) + if (x == x_parent->left) { + struct dbn* w = x_parent->right; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left(x_parent, root); + w = x_parent->right; + } + if ((w->left == NULL || + w->left->color == BLACK) && + (w->right == NULL || + w->right->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == NULL || + w->right->color == BLACK) { + if (w->left) w->left->color = BLACK; + w->color = RED; + db_rotate_right(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) w->right->color = BLACK; + db_rotate_left(x_parent, root); + break; + } + } else { // same as above, with right <-> left. + struct dbn* w = x_parent->left; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right(x_parent, root); + w = x_parent->left; + } + if ((w->right == NULL || + w->right->color == BLACK) && + (w->left == NULL || + w->left->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == NULL || + w->left->color == BLACK) { + if (w->right) w->right->color = BLACK; + w->color = RED; + db_rotate_left(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) w->left->color = BLACK; + db_rotate_right(x_parent, root); + break; + } + } + if (x) x->color = BLACK; + } +} + +struct dbn* db_insert(struct dbt *table,void* key,void* data) +{ + struct dbn *p,*priv; + int c,hash; + + hash = table->hash(table,key) % HASH_SIZE; + for(c=0,priv=NULL ,p = table->ht[hash];p;){ + c=table->cmp(table,key,p->key); + if(c==0){ // replace + if (table->release) + table->release(p, 3); + p->data=data; + p->key=key; + return p; + } + priv=p; + if(c<0){ + p=p->left; + } else { + p=p->right; + } + } +#ifdef MALLOC_DBN + p=malloc_dbn(); +#else + CREATE(p, struct dbn, 1); +#endif + if(p==NULL){ + printf("out of memory : db_insert\n"); + return NULL; + } + p->parent= NULL; + p->left = NULL; + p->right = NULL; + p->key = key; + p->data = data; + p->color = RED; + if(c==0){ // hash entry is empty + table->ht[hash] = p; + p->color = BLACK; + } else { + if(c<0){ // left node + priv->left = p; + p->parent=priv; + } else { // right node + priv->right = p; + p->parent=priv; + } + if(priv->color==RED){ // must rebalance + db_rebalance(p,&table->ht[hash]); + } + } + return p; +} + +void* db_erase(struct dbt *table,void* key) +{ + void *data; + struct dbn *p; + int c,hash; + + hash = table->hash(table,key) % HASH_SIZE; + for(c=0,p = table->ht[hash];p;){ + c=table->cmp(table,key,p->key); + if(c==0) + break; + if(c<0) + p=p->left; + else + p=p->right; + } + if(!p) + return NULL; + data=p->data; + db_rebalance_erase(p,&table->ht[hash]); +#ifdef MALLOC_DBN + free_dbn(p); +#else + free(p); +#endif + return data; +} + +void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...) +{ + int i,sp; + // red-black treeなので64個stackがあれば2^32個ノードまで大丈夫 + struct dbn *p,*pn,*stack[64]; + va_list ap; + + va_start(ap,func); + for(i=0;i<HASH_SIZE;i++){ + if((p=table->ht[i])==NULL) + continue; + sp=0; + while(1){ + func(p->key,p->data,ap); + if((pn=p->left)!=NULL){ + if(p->right){ + stack[sp++]=p->right; + } + p=pn; + } else { + if(p->right){ + p=p->right; + } else { + if(sp==0) + break; + p=stack[--sp]; + } + } + } + } + va_end(ap); +} + +void db_final(struct dbt *table,int (*func)(void*,void*,va_list),...) +{ + int i,sp; + struct dbn *p,*pn,*stack[64]; + va_list ap; + + va_start(ap,func); + for(i=0;i<HASH_SIZE;i++){ + if((p=table->ht[i])==NULL) + continue; + sp=0; + while(1){ + if(func) + func(p->key,p->data,ap); + if((pn=p->left)!=NULL){ + if(p->right){ + stack[sp++]=p->right; + } + } else { + if(p->right){ + pn=p->right; + } else { + if(sp==0) + break; + pn=stack[--sp]; + } + } +#ifdef MALLOC_DBN + free_dbn(p); +#else + free(p); +#endif + p=pn; + } + } + free(table); + va_end(ap); +} diff --git a/src/common/db.h b/src/common/db.h new file mode 100644 index 0000000..ea9acea --- /dev/null +++ b/src/common/db.h @@ -0,0 +1,47 @@ +#ifndef _DB_H_ +#define _DB_H_ + +#include <stdarg.h> + +#define HASH_SIZE (256+27) + +#define RED 0 +#define BLACK 1 + +struct dbn { + struct dbn *parent,*left,*right; + int color; + void *key; + void *data; +}; + +struct dbt { + int (*cmp)(struct dbt*,void*,void*); + unsigned int (*hash)(struct dbt*,void*); + // which 1 - key, 2 - data, 3 - both + void (*release)(struct dbn*,int which); + int maxlen; + struct dbn *ht[HASH_SIZE]; +}; + +#define strdb_search(t,k) db_search((t),(void*)(k)) +#define strdb_insert(t,k,d) db_insert((t),(void*)(k),(void*)(d)) +#define strdb_erase(t,k) db_erase ((t),(void*)(k)) +#define strdb_foreach db_foreach +#define strdb_final db_final +#define numdb_search(t,k) db_search((t),(void*)(k)) +#define numdb_insert(t,k,d) db_insert((t),(void*)(k),(void*)(d)) +#define numdb_erase(t,k) db_erase ((t),(void*)(k)) +#define numdb_foreach db_foreach +#define numdb_final db_final + +struct dbt* strdb_init(int maxlen); +struct dbt* numdb_init(void); +void* db_search(struct dbt *table,void* key); +void* db_search2(struct dbt *table, const char *key); // [MouseJstr] +struct dbn* db_insert(struct dbt *table,void* key,void* data); +void* db_erase(struct dbt *table,void* key); +void db_foreach(struct dbt*,int(*)(void*,void*,va_list),...); +void db_final(struct dbt*,int(*)(void*,void*,va_list),...); + +#endif diff --git a/src/common/grfio.c b/src/common/grfio.c new file mode 100644 index 0000000..08a8b2a --- /dev/null +++ b/src/common/grfio.c @@ -0,0 +1,948 @@ +/********************************************************************* + * + * 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" + +#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; + } + fread(buf2,1,lentry.declen,in); + 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); + fread(buf,1,entry->srclen_aligned,in); + 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 + fread(grf_header,1,0x2e,fp); + 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 + } + fread(grf_filelist,1,list_size,fp); + 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; + + fread(eheader,1,8,fp); + 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; + } + fread(rBuf,1,rSize,fp); + 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. + } +} diff --git a/src/common/grfio.h b/src/common/grfio.h new file mode 100644 index 0000000..53b9da8 --- /dev/null +++ b/src/common/grfio.h @@ -0,0 +1,16 @@ +// $Id: grfio.h,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +#ifndef _GRFIO_H_ +#define _GRFIO_H_ + +void grfio_init(char*); // GRFIO Initialize +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 +int grfio_size(char*); // GRFIO data file size get + +// Accessor to GRF filenames +char *grfio_setdatafile(const char *str); +char *grfio_setadatafile(const char *str); +char *grfio_setsdatafile(const char *str); + +#endif // _GRFIO_H_ diff --git a/src/common/lock.c b/src/common/lock.c new file mode 100644 index 0000000..9a2205b --- /dev/null +++ b/src/common/lock.c @@ -0,0 +1,37 @@ + +#include <stdio.h> +#include "lock.h" + +// 書き込みファイルの保護処理 +// (書き込みが終わるまで、旧ファイルを保管しておく) + +// 新しいファイルの書き込み開始 +FILE* lock_fopen(const char* filename,int *info) { + char newfile[512]; + FILE *fp; + int no = 0; + + // 安全なファイル名を得る(手抜き) + do { + sprintf(newfile,"%s_%04d.tmp",filename,++no); + } while((fp = fopen(newfile,"r")) && (fclose(fp), no<9999) ); + *info = no; + return fopen(newfile,"w"); +} + +// 旧ファイルを削除&新ファイルをリネーム +int lock_fclose(FILE *fp,const char* filename,int *info) { + int ret = 0; + char newfile[512]; + if(fp != NULL) { + ret = fclose(fp); + sprintf(newfile,"%s_%04d.tmp",filename,*info); + remove(filename); + // このタイミングで落ちると最悪。 + rename(newfile,filename); + return ret; + } else { + return 1; + } +} + diff --git a/src/common/lock.h b/src/common/lock.h new file mode 100644 index 0000000..795bf88 --- /dev/null +++ b/src/common/lock.h @@ -0,0 +1,8 @@ +#ifndef _LOCK_H_ +#define _LOCK_H_ + +FILE* lock_fopen(const char* filename,int *info); +int lock_fclose(FILE *fp,const char* filename,int *info); + +#endif + diff --git a/src/common/malloc.c b/src/common/malloc.c new file mode 100644 index 0000000..eda9bc2 --- /dev/null +++ b/src/common/malloc.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include "malloc.h" + +void* aMalloc_( size_t size, const char *file, int line, const char *func ) +{ + void *ret; + +// printf("%s:%d: in func %s: malloc %d\n",file,line,func,size); + ret=malloc(size); + if(ret==NULL){ + printf("%s:%d: in func %s: malloc error out of memory!\n",file,line,func); + exit(1); + + } + return ret; +} +void* aCalloc_( size_t num, size_t size, const char *file, int line, const char *func ) +{ + void *ret; + +// printf("%s:%d: in func %s: calloc %d %d\n",file,line,func,num,size); + ret=calloc(num,size); + if(ret==NULL){ + printf("%s:%d: in func %s: calloc error out of memory!\n",file,line,func); + exit(1); + + } + return ret; +} + +void* aRealloc_( void *p, size_t size, const char *file, int line, const char *func ) +{ + void *ret; + +// printf("%s:%d: in func %s: realloc %p %d\n",file,line,func,p,size); + ret=realloc(p,size); + if(ret==NULL){ + printf("%s:%d: in func %s: realloc error out of memory!\n",file,line,func); + exit(1); + + } + return ret; +} diff --git a/src/common/malloc.h b/src/common/malloc.h new file mode 100644 index 0000000..3733a5e --- /dev/null +++ b/src/common/malloc.h @@ -0,0 +1,25 @@ +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +#include <stdlib.h> + +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#endif + +#define ALC_MARK __FILE__, __LINE__, __func__ + +void* aMalloc_( size_t size, const char *file, int line, const char *func ); +void* aCalloc_( size_t num, size_t size, const char *file, int line, const char *func ); +void* aRealloc_( void *p, size_t size, const char *file, int line, const char *func ); + +#define aMalloc(n) aMalloc_(n,ALC_MARK) +#define aCalloc(m,n) aCalloc_(m,n,ALC_MARK) +#define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) + + +#endif diff --git a/src/common/mmo.h b/src/common/mmo.h new file mode 100644 index 0000000..4105135 --- /dev/null +++ b/src/common/mmo.h @@ -0,0 +1,304 @@ +// $Id: mmo.h,v 1.3 2004/09/25 20:12:25 PoW Exp $ +// Original : mmo.h 2003/03/14 12:07:02 Rev.1.7 + +#ifndef _MMO_H_ +#define _MMO_H_ + +#include <time.h> +#include "utils.h" // LCCWIN32 + +#ifdef CYGWIN +// txtやlogなどの書き出すファイルの改行コード +#define RETCODE "\r\n" // (CR/LF:Windows系) +#else +#define RETCODE "\n" // (LF:Unix系) +#endif + +#define FIFOSIZE_SERVERLINK 128*1024 + +// set to 0 to not check IP of player between each server. +// set to another value if you want to check (1) +#define CMP_AUTHFIFO_IP 1 + +#define CMP_AUTHFIFO_LOGIN2 1 + +#define MAX_MAP_PER_SERVER 512 +#define MAX_INVENTORY 100 +#define MAX_AMOUNT 30000 +#define MAX_ZENY 1000000000 // 1G zeny +#define MAX_CART 100 +#define MAX_SKILL 450 +#define GLOBAL_REG_NUM 96 +#define ACCOUNT_REG_NUM 16 +#define ACCOUNT_REG2_NUM 16 +#define DEFAULT_WALK_SPEED 150 +#define MIN_WALK_SPEED 0 +#define MAX_WALK_SPEED 1000 +#define MAX_STORAGE 300 +#define MAX_GUILD_STORAGE 1000 +#define MAX_PARTY 12 +#define MAX_GUILD 36 // increased max guild members to accomodate for +2 increase for extension levels [Valaris] (removed) [PoW] +#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +#define MAX_GUILDEXPLUSION 32 +#define MAX_GUILDALLIANCE 16 +#define MAX_GUILDSKILL 8 +#define MAX_GUILDCASTLE 24 // increased to include novice castles [Valaris] +#define MAX_GUILDLEVEL 50 + +#define MIN_HAIR_STYLE battle_config.min_hair_style +#define MAX_HAIR_STYLE battle_config.max_hair_style +#define MIN_HAIR_COLOR battle_config.min_hair_color +#define MAX_HAIR_COLOR battle_config.max_hair_color +#define MIN_CLOTH_COLOR battle_config.min_cloth_color +#define MAX_CLOTH_COLOR battle_config.max_cloth_color + +// for produce +#define MIN_ATTRIBUTE 0 +#define MAX_ATTRIBUTE 4 +#define ATTRIBUTE_NORMAL 0 +#define MIN_STAR 0 +#define MAX_STAR 3 + +#define MIN_PORTAL_MEMO 0 +#define MAX_PORTAL_MEMO 2 + +#define MAX_STATUS_TYPE 5 + +#define WEDDING_RING_M 2634 +#define WEDDING_RING_F 2635 + +#define CHAR_CONF_NAME "conf/char_athena.conf" + +struct item { + int id; + short nameid; + short amount; + unsigned short equip; + char identify; + char refine; + char attribute; + short card[4]; + short broken; +}; + +struct point{ + char map[24]; + short x,y; +}; + +struct skill { + unsigned short id,lv,flag; +}; + +struct global_reg { + char str[32]; + int value; +}; + +struct s_pet { + int account_id; + int char_id; + int pet_id; + short class; + short level; + short egg_id;//pet egg id + short equip;//pet equip name_id + short intimate;//pet friendly + short hungry;//pet hungry + char name[24]; + char rename_flag; + char incuvate; +}; + +struct mmo_charstatus { + int char_id; + int account_id; + int partner_id; + + int base_exp,job_exp,zeny; + + short class; + short status_point,skill_point; + int hp,max_hp,sp,max_sp; + short option,karma,manner; + short hair,hair_color,clothes_color; + int party_id,guild_id,pet_id; + + short weapon,shield; + short head_top,head_mid,head_bottom; + + char name[24]; + unsigned char base_level,job_level; + short str,agi,vit,int_,dex,luk; + unsigned char char_num,sex; + + unsigned long mapip; + unsigned int mapport; + + struct point last_point,save_point,memo_point[10]; + struct item inventory[MAX_INVENTORY],cart[MAX_CART]; + struct skill skill[MAX_SKILL]; + int global_reg_num; + struct global_reg global_reg[GLOBAL_REG_NUM]; + int account_reg_num; + struct global_reg account_reg[ACCOUNT_REG_NUM]; + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; +}; + +struct storage { + int account_id; + short storage_status; + short storage_amount; + struct item storage[MAX_STORAGE]; +}; + +struct guild_storage { + int guild_id; + short storage_status; + short storage_amount; + struct item storage[MAX_GUILD_STORAGE]; +}; + +struct map_session_data; + +struct gm_account { + int account_id; + int level; +}; + +struct party_member { + int account_id; + char name[24],map[24]; + int leader,online,lv; + struct map_session_data *sd; +}; + +struct party { + int party_id; + char name[24]; + int exp; + int item; + struct party_member member[MAX_PARTY]; +}; + +struct guild_member { + int account_id, char_id; + short hair,hair_color,gender,class,lv; + int exp,exp_payper; + short online,position; + int rsv1,rsv2; + char name[24]; + struct map_session_data *sd; +}; + +struct guild_position { + char name[24]; + int mode; + int exp_mode; +}; + +struct guild_alliance { + int opposition; + int guild_id; + char name[24]; +}; + +struct guild_explusion { + char name[24]; + char mes[40]; + char acc[40]; + int account_id; + int rsv1,rsv2,rsv3; +}; + +struct guild_skill { + int id,lv; +}; + +struct guild { + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + int exp,next_exp,skill_point,castle_id; + char name[24],master[24]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[60],mes2[120]; + int emblem_len,emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_explusion explusion[MAX_GUILDEXPLUSION]; + struct guild_skill skill[MAX_GUILDSKILL]; +}; + +struct guild_castle { + int castle_id; + char map_name[24]; + char castle_name[24]; + char castle_event[24]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + int visibleG0; + int visibleG1; + int visibleG2; + int visibleG3; + int visibleG4; + int visibleG5; + int visibleG6; + int visibleG7; + int Ghp0; // added Guardian HP [Valaris] + int Ghp1; + int Ghp2; + int Ghp3; + int Ghp4; + int Ghp5; + int Ghp6; + int Ghp7; + int GID0; + int GID1; + int GID2; + int GID3; + int GID4; + int GID5; + int GID6; + int GID7; // end addition [Valaris] +}; +struct square { + int val1[5]; + int val2[5]; +}; + +enum { + GBI_EXP =1, // ギルドのEXP + GBI_GUILDLV =2, // ギルドのLv + GBI_SKILLPOINT =3, // ギルドのスキルポイント + GBI_SKILLLV =4, // ギルドスキルLv + + GMI_POSITION =0, // メンバーの役職変更 + GMI_EXP =1, // メンバーのEXP + +}; + +#ifndef LCCWIN32 +#ifndef strcmpi +#define strcmpi strcasecmp +#endif +#ifndef stricmp +#define stricmp strcasecmp +#endif +#ifndef strncmpi +#define strncmpi strncasecmp +#endif +#ifndef strnicmp +#define strnicmp strncasecmp +#endif +#endif + +#endif // _MMO_H_ diff --git a/src/common/nullpo.c b/src/common/nullpo.c new file mode 100644 index 0000000..5fbf5fc --- /dev/null +++ b/src/common/nullpo.c @@ -0,0 +1,90 @@ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include "nullpo.h" +// #include "logs.h" // 布石してみる + +static void nullpo_info_core(const char *file, int line, const char *func, + const char *fmt, va_list ap); + +/*====================================== + * Nullチェック 及び 情報出力 + *-------------------------------------- + */ +int nullpo_chk_f(const char *file, int line, const char *func, const void *target, + const char *fmt, ...) +{ + va_list ap; + + if (target != NULL) + return 0; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); + return 1; +} + +int nullpo_chk(const char *file, int line, const char *func, const void *target) +{ + if (target != NULL) + return 0; + + nullpo_info_core(file, line, func, NULL, NULL); + return 1; +} + + +/*====================================== + * nullpo情報出力(外部呼出し向けラッパ) + *-------------------------------------- + */ +void nullpo_info_f(const char *file, int line, const char *func, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); +} + +void nullpo_info(const char *file, int line, const char *func) +{ + nullpo_info_core(file, line, func, NULL, NULL); +} + + +/*====================================== + * nullpo情報出力(Main) + *-------------------------------------- + */ +static void nullpo_info_core(const char *file, int line, const char *func, + const char *fmt, va_list ap) +{ + if (file == NULL) + file = "??"; + + func = + func == NULL ? "unknown": + func[0] == '\0' ? "unknown": + func; + + printf("--- nullpo info --------------------------------------------\n"); + printf("%s:%d: in func `%s'\n", file, line, func); + if (fmt != NULL) + { + if (fmt[0] != '\0') + { + vprintf(fmt, ap); + + // 最後に改行したか確認 + if (fmt[strlen(fmt)-1] != '\n') + printf("\n"); + } + } + printf("--- end nullpo info ----------------------------------------\n"); + + // ここらでnullpoログをファイルに書き出せたら + // まとめて提出できるなと思っていたり。 +} diff --git a/src/common/nullpo.h b/src/common/nullpo.h new file mode 100644 index 0000000..2d33500 --- /dev/null +++ b/src/common/nullpo.h @@ -0,0 +1,222 @@ +#ifndef _NULLPO_H_ +#define _NULLPO_H_ + + +#define NULLPO_CHECK 1 + // 全体のスイッチを宣言しているヘッダがあれば + // そこに移動していただけると + + +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#endif + +#ifdef LCCWIN32 +#define __attribute__(x) /* nothing */ +#endif + + +#define NLP_MARK __FILE__, __LINE__, __func__ + +/*---------------------------------------------------------------------------- + * Macros + *---------------------------------------------------------------------------- + */ +/*====================================== + * Nullチェック 及び 情報出力後 return + *・展開するとifとかreturn等が出るので + * 一行単体で使ってください。 + *・nullpo_ret(x = func()); + * のような使用法も想定しています。 + *-------------------------------------- + * nullpo_ret(t) + * 戻り値 0固定 + * [引数] + * t チェック対象 + *-------------------------------------- + * nullpo_retv(t) + * 戻り値 なし + * [引数] + * t チェック対象 + *-------------------------------------- + * nullpo_retr(ret, t) + * 戻り値 指定 + * [引数] + * ret return(ret); + * t チェック対象 + *-------------------------------------- + * nullpo_ret_f(t, fmt, ...) + * 詳細情報出力用 + * 戻り値 0 + * [引数] + * t チェック対象 + * fmt ... vprintfに渡される + * 備考や関係変数の書き出しなどに + *-------------------------------------- + * nullpo_retv_f(t, fmt, ...) + * 詳細情報出力用 + * 戻り値 なし + * [引数] + * t チェック対象 + * fmt ... vprintfに渡される + * 備考や関係変数の書き出しなどに + *-------------------------------------- + * nullpo_retr_f(ret, t, fmt, ...) + * 詳細情報出力用 + * 戻り値 指定 + * [引数] + * ret return(ret); + * t チェック対象 + * fmt ... vprintfに渡される + * 備考や関係変数の書き出しなどに + *-------------------------------------- + */ + +#if NULLPO_CHECK + +#define nullpo_ret(t) \ + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} + +#define nullpo_retv(t) \ + if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} + +#define nullpo_retr(ret, t) \ + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} + + +// 可変引数マクロに関する条件コンパイル +#if __STDC_VERSION__ >= 199901L +/* C99に対応 */ +#define nullpo_ret_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} + +#define nullpo_retv_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} + +#define nullpo_retr_f(ret, t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} + +#elif __GNUC__ >= 2 +/* GCC用 */ +#define nullpo_ret_f(t, fmt, args...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} + +#define nullpo_retv_f(t, fmt, args...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} + +#define nullpo_retr_f(ret, t, fmt, args...) \ + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} + +#else + +/* その他の場合・・・ orz */ + +#endif + +#else /* NULLPO_CHECK */ +/* No Nullpo check */ + +// if((t)){;} +// 良い方法が思いつかなかったので・・・苦肉の策です。 +// 一応ワーニングは出ないはず + +#define nullpo_ret(t) if((t)){;} +#define nullpo_retv(t) if((t)){;} +#define nullpo_retr(ret, t) if((t)){;} + +// 可変引数マクロに関する条件コンパイル +#if __STDC_VERSION__ >= 199901L +/* C99に対応 */ +#define nullpo_ret_f(t, fmt, ...) if((t)){;} +#define nullpo_retv_f(t, fmt, ...) if((t)){;} +#define nullpo_retr_f(ret, t, fmt, ...) if((t)){;} + +#elif __GNUC__ >= 2 +/* GCC用 */ +#define nullpo_ret_f(t, fmt, args...) if((t)){;} +#define nullpo_retv_f(t, fmt, args...) if((t)){;} +#define nullpo_retr_f(ret, t, fmt, args...) if((t)){;} + +#else +/* その他の場合・・・ orz */ +#endif + +#endif /* NULLPO_CHECK */ + +/*---------------------------------------------------------------------------- + * Functions + *---------------------------------------------------------------------------- + */ +/*====================================== + * nullpo_chk + * Nullチェック 及び 情報出力 + * [引数] + * file __FILE__ + * line __LINE__ + * func __func__ (関数名) + * これらには NLP_MARK を使うとよい + * target チェック対象 + * [返り値] + * 0 OK + * 1 NULL + *-------------------------------------- + */ +int nullpo_chk(const char *file, int line, const char *func, const void *target); + + +/*====================================== + * nullpo_chk_f + * Nullチェック 及び 詳細な情報出力 + * [引数] + * file __FILE__ + * line __LINE__ + * func __func__ (関数名) + * これらには NLP_MARK を使うとよい + * target チェック対象 + * fmt ... vprintfに渡される + * 備考や関係変数の書き出しなどに + * [返り値] + * 0 OK + * 1 NULL + *-------------------------------------- + */ +int nullpo_chk_f(const char *file, int line, const char *func, const void *target, + const char *fmt, ...) + __attribute__((format(printf,5,6))); + + +/*====================================== + * nullpo_info + * nullpo情報出力 + * [引数] + * file __FILE__ + * line __LINE__ + * func __func__ (関数名) + * これらには NLP_MARK を使うとよい + *-------------------------------------- + */ +void nullpo_info(const char *file, int line, const char *func); + + +/*====================================== + * nullpo_info_f + * nullpo詳細情報出力 + * [引数] + * file __FILE__ + * line __LINE__ + * func __func__ (関数名) + * これらには NLP_MARK を使うとよい + * fmt ... vprintfに渡される + * 備考や関係変数の書き出しなどに + *-------------------------------------- + */ +void nullpo_info_f(const char *file, int line, const char *func, + const char *fmt, ...) + __attribute__((format(printf,4,5))); + + +#endif diff --git a/src/common/socket.c b/src/common/socket.c new file mode 100644 index 0000000..1711286 --- /dev/null +++ b/src/common/socket.c @@ -0,0 +1,439 @@ +// $Id: socket.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +// original : core.c 2003/02/26 18:03:12 Rev 1.7 + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +#ifdef LCCWIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winsock2.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/time.h> +#include <unistd.h> +#endif + +#include <fcntl.h> +#include <string.h> + +#include "mmo.h" // [Valaris] thanks to fov +#include "socket.h" +#include "utils.h" + +#ifdef MEMWATCH +#include "memwatch.h" +#endif + +fd_set readfds; +int fd_max; + +int rfifo_size = 65536; +int wfifo_size = 65536; + +struct socket_data *session[FD_SETSIZE]; + +static int null_parse(int fd); +static int (*default_func_parse)(int) = null_parse; + +/*====================================== + * CORE : Set function + *-------------------------------------- + */ +void set_defaultparse(int (*defaultparse)(int)) +{ + default_func_parse = defaultparse; +} + +/*====================================== + * CORE : Socket Sub Function + *-------------------------------------- + */ + +static int recv_to_fifo(int fd) +{ + int len; + + //printf("recv_to_fifo : %d %d\n",fd,session[fd]->eof); + if(session[fd]->eof) + return -1; + + +#ifdef LCCWIN32 + len = recv(fd,session[fd]->rdata+session[fd]->rdata_size, RFIFOSPACE(fd), 0); +#else + len=read(fd,session[fd]->rdata+session[fd]->rdata_size,RFIFOSPACE(fd)); +#endif + +// printf (":::RECEIVE:::\n"); +// dump(session[fd]->rdata, len); printf ("\n"); + + //{ int i; printf("recv %d : ",fd); for(i=0;i<len;i++){ printf("%02x ",RFIFOB(fd,session[fd]->rdata_size+i)); } printf("\n");} + if(len>0){ + session[fd]->rdata_size+=len; + } else if(len<=0){ + // value of connection is not necessary the same +// if (fd == 4) // Removed [Yor] +// printf("Char-Server Has Disconnected.\n"); +// else if (fd == 5) // Removed [Yor] +// printf("Attempt To Log In Successful.\n"); +// else if (fd == 7) // Removed [Yor] +// printf("Char-Server Has Disconnected.\n"); +// else if (fd == 8) // Removed [Valaris] +// printf("%s has logged off your server.\n",RFIFOP(fd,6)); // Removed [Valaris] + +// else if (fd != 8) // [Valaris] + printf("set eof : connection #%d\n", fd); + session[fd]->eof=1; + } + return 0; +} + +static int send_from_fifo(int fd) +{ + int len; + + //printf("send_from_fifo : %d\n",fd); + if(session[fd]->eof) + return -1; + +#ifdef LCCWIN32 + len = send(fd, session[fd]->wdata,session[fd]->wdata_size, 0); +#else + len=write(fd,session[fd]->wdata,session[fd]->wdata_size); +#endif + +// printf (":::SEND:::\n"); +// dump(session[fd]->wdata, len); printf ("\n"); + + //{ int i; printf("send %d : ",fd); for(i=0;i<len;i++){ printf("%02x ",session[fd]->wdata[i]); } printf("\n");} + if(len>0){ + if(len<session[fd]->wdata_size){ + memmove(session[fd]->wdata,session[fd]->wdata+len,session[fd]->wdata_size-len); + session[fd]->wdata_size-=len; + } else { + session[fd]->wdata_size=0; + } + } else { + printf("set eof :%d\n",fd); + session[fd]->eof=1; + } + return 0; +} + +static int null_parse(int fd) +{ + printf("null_parse : %d\n",fd); + RFIFOSKIP(fd,RFIFOREST(fd)); + return 0; +} + +/*====================================== + * CORE : Socket Function + *-------------------------------------- + */ + +static int connect_client(int listen_fd) +{ + int fd; + struct sockaddr_in client_address; + int len; + int result; + int yes = 1; // reuse fix + + //printf("connect_client : %d\n",listen_fd); + + len=sizeof(client_address); + + fd=accept(listen_fd,(struct sockaddr*)&client_address,&len); + if(fd_max<=fd) fd_max=fd+1; + +// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof yes); // reuse fix +#ifdef SO_REUSEPORT +// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof yes); //reuse fix +#endif +// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); + setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,(char *)&yes,sizeof yes); // reuse fix + + if(fd==-1){ + perror("accept"); + } else { + FD_SET(fd,&readfds); + } + +#ifdef LCCWIN32 + { + unsigned long val = 1; + ioctlsocket(fd, FIONBIO, &val); + } +#else + result = fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + + CREATE(session[fd], struct socket_data, 1); + CREATE(session[fd]->rdata, char, rfifo_size); + CREATE(session[fd]->wdata, char, wfifo_size); + + session[fd]->max_rdata = rfifo_size; + session[fd]->max_wdata = wfifo_size; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + session[fd]->client_addr = client_address; + + //printf("new_session : %d %d\n",fd,session[fd]->eof); + return fd; +} + +int make_listen_port(int port) +{ + struct sockaddr_in server_address; + int fd; + int result; + int yes = 1; // reuse fix + + fd = socket( AF_INET, SOCK_STREAM, 0 ); + if(fd_max<=fd) fd_max=fd+1; + +#ifdef LCCWIN32 + { + unsigned long val = 1; + ioctlsocket(fd, FIONBIO, &val); + } +#else + result = fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + +// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof yes); // reuse fix +#ifdef SO_REUSEPORT +// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof yes); //reuse fix +#endif +// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); + setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,(char *)&yes,sizeof yes); // reuse fix + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl( INADDR_ANY ); + server_address.sin_port = htons(port); + + result = bind(fd, (struct sockaddr*)&server_address, sizeof(server_address)); + if( result == -1 ) { + perror("bind"); + exit(1); + } + result = listen( fd, 5 ); + if( result == -1 ) { /* error */ + perror("listen"); + exit(1); + } + + FD_SET(fd, &readfds ); + + CREATE(session[fd], struct socket_data, 1); + + if(session[fd]==NULL){ + printf("out of memory : make_listen_port\n"); + exit(1); + } + memset(session[fd],0,sizeof(*session[fd])); + session[fd]->func_recv = connect_client; + + return fd; +} + +int make_connection(long ip,int port) +{ + struct sockaddr_in server_address; + int fd; + int result; + int yes = 1; // reuse fix + + fd = socket( AF_INET, SOCK_STREAM, 0 ); + if(fd_max<=fd) fd_max=fd+1; +// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof yes); // reuse fix +#ifdef SO_REUSEPORT +// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); + setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof yes); //reuse fix +#endif +// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); + setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,(char *)&yes,sizeof yes); // reuse fix + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = ip; + server_address.sin_port = htons(port); + +#ifdef LCCWIN32 + { + unsigned long val = 1; + ioctlsocket(fd, FIONBIO, &val); + } +#else + result = fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + + result = connect(fd, (struct sockaddr *)(&server_address),sizeof(struct sockaddr_in)); + + FD_SET(fd,&readfds); + + CREATE(session[fd], struct socket_data, 1); + CREATE(session[fd]->rdata, char, rfifo_size); + CREATE(session[fd]->wdata, char, wfifo_size); + + session[fd]->max_rdata = rfifo_size; + session[fd]->max_wdata = wfifo_size; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + + return fd; +} + +int delete_session(int fd) +{ + if(fd<0 || fd>=FD_SETSIZE) + return -1; + FD_CLR(fd,&readfds); + if(session[fd]){ + if(session[fd]->rdata) + free(session[fd]->rdata); + if(session[fd]->wdata) + free(session[fd]->wdata); + if(session[fd]->session_data) + free(session[fd]->session_data); + free(session[fd]); + } + session[fd]=NULL; + //printf("delete_session:%d\n",fd); + return 0; +} + +int realloc_fifo(int fd,int rfifo_size,int wfifo_size) +{ + struct socket_data *s=session[fd]; + if( s->max_rdata != rfifo_size && s->rdata_size < rfifo_size){ + RECREATE(s->rdata, char, rfifo_size); + s->max_rdata = rfifo_size; + } + if( s->max_wdata != wfifo_size && s->wdata_size < wfifo_size){ + RECREATE(s->wdata, char, wfifo_size); + s->max_wdata = wfifo_size; + } + return 0; +} + +int WFIFOSET(int fd,int len) +{ + struct socket_data *s=session[fd]; + if( s->wdata_size+len+16384 > s->max_wdata ){ + realloc_fifo(fd,s->max_rdata, s->max_wdata <<1 ); + printf("socket: %d wdata expanded to %d bytes.\n",fd, s->max_wdata); + } + s->wdata_size=(s->wdata_size+(len)+2048 < s->max_wdata) ? + s->wdata_size+len : (printf("socket: %d wdata lost !!\n",fd),s->wdata_size); + return 0; +} + +int do_sendrecv(int next) +{ + fd_set rfd,wfd; + struct timeval timeout; + int ret,i; + + rfd=readfds; + FD_ZERO(&wfd); + for(i=0;i<fd_max;i++){ + if(!session[i] && FD_ISSET(i,&readfds)){ + printf("force clr fds %d\n",i); + FD_CLR(i,&readfds); + continue; + } + if(!session[i]) + continue; + if(session[i]->wdata_size) + FD_SET(i,&wfd); + } + timeout.tv_sec = next/1000; + timeout.tv_usec = next%1000*1000; + ret = select(fd_max,&rfd,&wfd,NULL,&timeout); + if(ret<=0) + return 0; + for(i=0;i<fd_max;i++){ + if(!session[i]) + continue; + if(FD_ISSET(i,&wfd)){ + //printf("write:%d\n",i); + if(session[i]->func_send) + //send_from_fifo(i); + session[i]->func_send(i); + } + if(FD_ISSET(i,&rfd)){ + //printf("read:%d\n",i); + if(session[i]->func_recv) + //recv_to_fifo(i); + session[i]->func_recv(i); + } + } + return 0; +} + +int do_parsepacket(void) +{ + int i; + for(i=0;i<fd_max;i++){ + if(!session[i]) + continue; + if(session[i]->rdata_size==0 && session[i]->eof==0) + continue; + if(session[i]->func_parse){ + session[i]->func_parse(i); + if(!session[i]) + continue; + } + RFIFOFLUSH(i); + } + return 0; +} + +void do_socket(void) +{ + FD_ZERO(&readfds); +} + +int RFIFOSKIP(int fd,int len) +{ + struct socket_data *s=session[fd]; + + if (s->rdata_size-s->rdata_pos-len<0) { + fprintf(stderr,"too many skip\n"); + exit(1); + } + + s->rdata_pos = s->rdata_pos+len; + + return 0; +} + + +int Net_Init(void) +{ + #ifdef LCCWIN32 + /* Start up the windows networking */ + WORD version_wanted = MAKEWORD(1,1); + WSADATA wsaData; + + if ( WSAStartup(version_wanted, &wsaData) != 0 ) { + printf("SYSERR: WinSock not available!\n"); + exit(1); + } + #endif + + return(0); +} + diff --git a/src/common/socket.h b/src/common/socket.h new file mode 100644 index 0000000..fe06e40 --- /dev/null +++ b/src/common/socket.h @@ -0,0 +1,96 @@ +// original : core.h 2003/03/14 11:55:25 Rev 1.4 + +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + +#include <stdio.h> + +#ifdef LCCWIN32 +#include <winsock.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +// define declaration + +#define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos)) +#define RFIFOB(fd,pos) (*(unsigned char*)(session[fd]->rdata+session[fd]->rdata_pos+(pos))) +#define RFIFOW(fd,pos) (*(unsigned short*)(session[fd]->rdata+session[fd]->rdata_pos+(pos))) +#define RFIFOL(fd,pos) (*(unsigned int*)(session[fd]->rdata+session[fd]->rdata_pos+(pos))) +//#define RFIFOSKIP(fd,len) ((session[fd]->rdata_size-session[fd]->rdata_pos-(len)<0) ? (fprintf(stderr,"too many skip\n"),exit(1)) : (session[fd]->rdata_pos+=(len))) +#define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos) +#define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),session[fd]->rdata_size=RFIFOREST(fd),session[fd]->rdata_pos=0) +#define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size) +#define RBUFP(p,pos) (((unsigned char*)(p))+(pos)) +#define RBUFB(p,pos) (*(unsigned char*)RBUFP((p),(pos))) +#define RBUFW(p,pos) (*(unsigned short*)RBUFP((p),(pos))) +#define RBUFL(p,pos) (*(unsigned int*)RBUFP((p),(pos))) + +#define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size) +#define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos)) +#define WFIFOB(fd,pos) (*(unsigned char*)(session[fd]->wdata+session[fd]->wdata_size+(pos))) +#define WFIFOW(fd,pos) (*(unsigned short*)(session[fd]->wdata+session[fd]->wdata_size+(pos))) +#define WFIFOL(fd,pos) (*(unsigned int*)(session[fd]->wdata+session[fd]->wdata_size+(pos))) +// use function instead of macro. +//#define WFIFOSET(fd,len) (session[fd]->wdata_size = (session[fd]->wdata_size+(len)+2048 < session[fd]->max_wdata) ? session[fd]->wdata_size+len : session[fd]->wdata_size) +#define WBUFP(p,pos) (((unsigned char*)(p))+(pos)) +#define WBUFB(p,pos) (*(unsigned char*)WBUFP((p),(pos))) +#define WBUFW(p,pos) (*(unsigned short*)WBUFP((p),(pos))) +#define WBUFL(p,pos) (*(unsigned int*)WBUFP((p),(pos))) + +#ifdef __INTERIX +#define FD_SETSIZE 4096 +#endif // __INTERIX + + +/* Removed Cygwin FD_SETSIZE declarations, now are directly passed on to the compiler through Makefile [Valaris] */ + +// Struct declaration + +struct socket_data{ + int eof; + unsigned char *rdata,*wdata; + int max_rdata,max_wdata; + int rdata_size,wdata_size; + int rdata_pos; + struct sockaddr_in client_addr; + int (*func_recv)(int); + int (*func_send)(int); + int (*func_parse)(int); + void* session_data; +}; + +// Data prototype declaration + +#ifdef LCCWIN32 + + #undef FD_SETSIZE + #define FD_SETSIZE 4096 + +#endif + +extern struct socket_data *session[FD_SETSIZE]; + +extern int rfifo_size,wfifo_size; +extern int fd_max; + +// Function prototype declaration + +int make_listen_port(int); +int make_connection(long,int); +int delete_session(int); +int realloc_fifo(int fd,int rfifo_size,int wfifo_size); +int WFIFOSET(int fd,int len); +int RFIFOSKIP(int fd,int len); + +int do_sendrecv(int next); +int do_parsepacket(void); +void do_socket(void); + +void set_defaultparse(int (*defaultparse)(int)); + +int Net_Init(void); + +#endif // _SOCKET_H_ diff --git a/src/common/timer.c b/src/common/timer.c new file mode 100644 index 0000000..8193ff9 --- /dev/null +++ b/src/common/timer.c @@ -0,0 +1,312 @@ +// $Id: timer.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +// original : core.c 2003/02/26 18:03:12 Rev 1.7 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#ifdef LCCWIN32 +#include <winsock.h> +#else +#include <sys/socket.h> +#include <sys/time.h> +#endif + +#include "timer.h" +#include "utils.h" + +#ifdef MEMWATCH +#include "memwatch.h" +#endif + +static struct TimerData* timer_data; +static int timer_data_max,timer_data_num; +static int* free_timer_list; +static int free_timer_list_max, free_timer_list_pos; + +static int timer_heap_max; +static int* timer_heap = NULL; + +// for debug +struct timer_func_list { + int (*func)(int,unsigned int,int,int); + struct timer_func_list* next; + char* name; +}; +static struct timer_func_list* tfl_root; + +#if defined(LCCWIN32) +void gettimeofday(struct timeval *t, struct timezone *dummy) +{ + DWORD millisec = GetTickCount(); + + t->tv_sec = (int) (millisec / 1000); + t->tv_usec = (millisec % 1000) * 1000; +} + +#endif + + +// +int add_timer_func_list(int (*func)(int,unsigned int,int,int),char* name) +{ + struct timer_func_list* tfl; + + CREATE(tfl, struct timer_func_list, 1); + CREATE(tfl->name, char, strlen(name) + 1); + + tfl->next = tfl_root; + tfl->func = func; + strcpy(tfl->name,name); + tfl_root = tfl; + + return 0; +} + +char* search_timer_func_list(int (*func)(int,unsigned int,int,int)) +{ + struct timer_func_list* tfl; + for(tfl = tfl_root;tfl;tfl = tfl->next) { + if (func == tfl->func) + return tfl->name; + } + return "???"; +} + +/*---------------------------- + * Get tick time + *----------------------------*/ +static unsigned int gettick_cache; +static int gettick_count; +unsigned int gettick_nocache(void) +{ + struct timeval tval; + gettimeofday(&tval,NULL); + gettick_count = 256; + return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec/1000; +} + +unsigned int gettick(void) +{ + gettick_count--; + if (gettick_count<0) + return gettick_nocache(); + return gettick_cache; +} + +/*====================================== + * CORE : Timer Heap + *-------------------------------------- + */ +static void push_timer_heap(int index) +{ + int i, h; + + if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) { + int first = timer_heap == NULL; + + timer_heap_max += 256; + RECREATE(timer_heap, int, timer_heap_max); + memset(timer_heap + (timer_heap_max - 256), 0, sizeof(int) * 256); + if (first) + timer_heap[0] = 0; + } + + timer_heap[0]++; + + for (h = timer_heap[0]-1, i = (h - 1) / 2; + h > 0 && DIFF_TICK(timer_data[index].tick, + timer_data[timer_heap[i + 1]].tick) < 0; + i = (h - 1) / 2) { + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + } + timer_heap[h + 1] = index; +} + +static int top_timer_heap() +{ + if (timer_heap == NULL || timer_heap[0] <= 0) + return -1; + + return timer_heap[1]; +} + +static int pop_timer_heap() +{ + int i,h,k; + int ret,last; + + if (timer_heap == NULL || timer_heap[0] <= 0) + return -1; + ret = timer_heap[1]; + last = timer_heap[timer_heap[0]]; + timer_heap[0]--; + + for(h = 0,k = 2;k<timer_heap[0];k = k * 2 + 2) { + if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick , timer_data[timer_heap[k]].tick)>0) + k--; + timer_heap[h + 1] = timer_heap[k + 1], h = k; + } + if (k == timer_heap[0]) + timer_heap[h + 1] = timer_heap[k], h = k-1; + + for(i = (h-1)/2; + h>0 && DIFF_TICK(timer_data[timer_heap[i + 1]].tick , timer_data[last].tick)>0; + i = (h-1)/2) { + timer_heap[h + 1] = timer_heap[i + 1],h = i; + } + timer_heap[h + 1] = last; + + return ret; +} + +int add_timer(unsigned int tick,int (*func)(int,unsigned int,int,int),int id,int data) +{ + struct TimerData* td; + int i; + + if (free_timer_list_pos) { + do { + i = free_timer_list[--free_timer_list_pos]; + } while(i >= timer_data_num && free_timer_list_pos > 0); + } else + i = timer_data_num; + if (i >= timer_data_num) + for (i = timer_data_num;i<timer_data_max && timer_data[i].type; i++); + if (i >= timer_data_num && i >= timer_data_max) { + int j; + if (timer_data_max == 0) { + timer_data_max = 256; + CREATE(timer_data, struct TimerData, timer_data_max); + } else { + timer_data_max += 256; + RECREATE(timer_data, struct TimerData, timer_data_max); + if (timer_data == NULL) { + printf("out of memory : add_timer timer_data\n"); + exit(1); + } + memset(timer_data + (timer_data_max - 256), 0, + sizeof(struct TimerData) * 256); + } + for(j = timer_data_max-256;j<timer_data_max; j++) + timer_data[j].type = 0; + } + td = &timer_data[i]; + td->tick = tick; + td->func = func; + td->id = id; + td->data = data; + td->type = TIMER_ONCE_AUTODEL; + td->interval = 1000; + push_timer_heap(i); + if (i >= timer_data_num) + timer_data_num = i + 1; + return i; +} + +int add_timer_interval(unsigned int tick,int (*func)(int,unsigned int,int,int),int id,int data,int interval) +{ + int tid; + tid = add_timer(tick,func,id,data); + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + return tid; +} + +int delete_timer(int id,int (*func)(int,unsigned int,int,int)) +{ + if (id <= 0 || id >= timer_data_num) { + printf("delete_timer error : no such timer %d\n", id); + return -1; + } + if (timer_data[id].func != func) { + printf("delete_timer error : function dismatch %08x(%s) != %08x(%s)\n", + (int)timer_data[id].func, + search_timer_func_list(timer_data[id].func), + (int)func, + search_timer_func_list(func)); + return -2; + } + // そのうち消えるにまかせる + timer_data[id].func = NULL; + timer_data[id].type = TIMER_ONCE_AUTODEL; + timer_data[id].tick -= 60 * 60 * 1000; + return 0; +} + +int addtick_timer(int tid,unsigned int tick) +{ + return timer_data[tid].tick += tick; +} +struct TimerData* get_timer(int tid) +{ + return &timer_data[tid]; +} + + +int do_timer(unsigned int tick) +{ + int i,nextmin = 1000; + +#if 0 + static int disp_tick = 0; + if (DIFF_TICK(disp_tick,tick)<-5000 || DIFF_TICK(disp_tick,tick)>5000) { + printf("timer %d(%d + %d)\n",timer_data_num,timer_heap[0],free_timer_list_pos); + disp_tick = tick; + } +#endif + + while((i = top_timer_heap()) >= 0) { + if (DIFF_TICK(timer_data[i].tick , tick)>0) { + nextmin = DIFF_TICK(timer_data[i].tick , tick); + break; + } + pop_timer_heap(); + timer_data[i].type |= TIMER_REMOVE_HEAP; + if (timer_data[i].func) { + if (DIFF_TICK(timer_data[i].tick , tick) < -1000) { + // 1秒以上の大幅な遅延が発生しているので、 + // timer処理タイミングを現在値とする事で + // 呼び出し時タイミング(引数のtick)相対で処理してる + // timer関数の次回処理タイミングを遅らせる + timer_data[i].func(i,tick,timer_data[i].id,timer_data[i].data); + } else { + timer_data[i].func(i,timer_data[i].tick,timer_data[i].id,timer_data[i].data); + } + } + if (timer_data[i].type&TIMER_REMOVE_HEAP) { + switch(timer_data[i].type & ~TIMER_REMOVE_HEAP) { + case TIMER_ONCE_AUTODEL: + timer_data[i].type = 0; + if (free_timer_list_pos >= free_timer_list_max) { + free_timer_list_max += 256; + RECREATE(free_timer_list, int, free_timer_list_max); + memset(free_timer_list + (free_timer_list_max - 256), 0, + 256 * sizeof(free_timer_list[0])); + } + free_timer_list[free_timer_list_pos++] = i; + break; + case TIMER_INTERVAL: + if (DIFF_TICK(timer_data[i].tick , tick) < -1000) { + timer_data[i].tick = tick + timer_data[i].interval; + } else { + timer_data[i].tick += timer_data[i].interval; + } + timer_data[i].type &= ~TIMER_REMOVE_HEAP; + push_timer_heap(i); + break; + } + } + } + + if (nextmin<10) + nextmin = 10; + return nextmin; +} + +void timer_final() +{ + free(timer_data); +} diff --git a/src/common/timer.h b/src/common/timer.h new file mode 100644 index 0000000..f6fc5c8 --- /dev/null +++ b/src/common/timer.h @@ -0,0 +1,45 @@ +// original : core.h 2003/03/14 11:55:25 Rev 1.4 + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#define BASE_TICK 5 + +#define TIMER_ONCE_AUTODEL 1 +#define TIMER_INTERVAL 2 +#define TIMER_REMOVE_HEAP 16 + +#define DIFF_TICK(a,b) ((int)((a)-(b))) + +// Struct declaration + +struct TimerData { + unsigned int tick; + int (*func)(int,unsigned int,int,int); + int id; + int data; + int type; + int interval; + int heap_pos; +}; + +// Function prototype declaration + +unsigned int gettick_nocache(void); +unsigned int gettick(void); + +int add_timer(unsigned int,int (*)(int,unsigned int,int,int),int,int); +int add_timer_interval(unsigned int,int (*)(int,unsigned int,int,int),int,int,int); +int delete_timer(int,int (*)(int,unsigned int,int,int)); + +int addtick_timer(int tid,unsigned int tick); +struct TimerData *get_timer(int tid); + +int do_timer(unsigned int tick); + +int add_timer_func_list(int (*)(int,unsigned int,int,int),char*); +char* search_timer_func_list(int (*)(int,unsigned int,int,int)); + +extern void timer_final(); + +#endif // _TIMER_H_ diff --git a/src/common/utils.c b/src/common/utils.c new file mode 100644 index 0000000..b0ecd26 --- /dev/null +++ b/src/common/utils.c @@ -0,0 +1,108 @@ +#include <string.h> +#include "utils.h" +#include <stdio.h> + +void dump(unsigned char *buffer, int num) +{ + int icnt,jcnt; + + printf(" Hex ASCII\n"); + printf(" ----------------------------------------------- ----------------"); + + for (icnt=0;icnt<num;icnt+=16) { + printf("\n%p ",&buffer[icnt]); + for (jcnt=icnt;jcnt<icnt+16;++jcnt) { + if (jcnt < num) { + printf("%02hX ",buffer[jcnt]); + } else + printf(" "); + } + + printf(" | "); + + for (jcnt=icnt;jcnt<icnt+16;++jcnt) { + if (jcnt < num) { + if (buffer[jcnt] > 31 && buffer[jcnt] < 127) + printf("%c",buffer[jcnt]); + else + printf("."); + } else + printf(" "); + } + } + printf("\n"); +} + + +#ifdef LCCWIN32 +char *rindex(char *str, char c) +{ + char *sptr; + + sptr = str; + while(*sptr) + ++sptr; + if (c == '\0') + return(sptr); + while(str != sptr) + if (*sptr-- == c) + return(++sptr); + return(NULL); +} + +int strcasecmp(const char *arg1, const char *arg2) +{ + int chk, i; + + if (arg1 == NULL || arg2 == NULL) { + printf("SYSERR: str_cmp() passed a NULL pointer, %p or %p.\n", arg1, arg2); + return (0); + } + + for (i = 0; arg1[i] || arg2[i]; i++) + if ((chk = LOWER(arg1[i]) - LOWER(arg2[i])) != 0) + return (chk); /* not equal */ + + return (0); +} + +int strncasecmp(const char *arg1, const char *arg2, int n) +{ + int chk, i; + + if (arg1 == NULL || arg2 == NULL) { + printf("SYSERR: strn_cmp() passed a NULL pointer, %p or %p.\n", arg1, arg2); + return (0); + } + + for (i = 0; (arg1[i] || arg2[i]) && (n > 0); i++, n--) + if ((chk = LOWER(arg1[i]) - LOWER(arg2[i])) != 0) + return (chk); /* not equal */ + + return (0); +} + +void str_upper(char *name) +{ + + int len = strlen(name); + while (len--) { + if (*name >= 'a' && *name <= 'z') + *name -= ('a' - 'A'); + name++; + } +} + +void str_lower(char *name) +{ + int len = strlen(name); + + while (len--) { + if (*name >= 'A' && *name <= 'Z') + *name += ('a' - 'A'); + name++; + } +} + +#endif + diff --git a/src/common/utils.h b/src/common/utils.h new file mode 100644 index 0000000..29463cf --- /dev/null +++ b/src/common/utils.h @@ -0,0 +1,33 @@ + +#ifndef NULL +#define NULL (void *)0 +#endif + +#define LOWER(c) (((c)>='A' && (c) <= 'Z') ? ((c)+('a'-'A')) : (c)) +#define UPPER(c) (((c)>='a' && (c) <= 'z') ? ((c)+('A'-'a')) : (c) ) + +/* strcasecmp -> stricmp -> str_cmp */ + + +#ifdef LCCWIN32 + int strcasecmp(const char *arg1, const char *arg2); + int strncasecmp(const char *arg1, const char *arg2, int n); + void str_upper(char *name); + void str_lower(char *name); + char *rindex(char *str, char c); +#endif + + + void dump(unsigned char *buffer, int num); + + +#define CREATE(result, type, number) do {\ + if ((number) * sizeof(type) <= 0) \ + printf("SYSERR: Zero bytes or less requested at %s:%d.\n", __FILE__, __LINE__); \ + if (!((result) = (type *) calloc ((number), sizeof(type)))) \ + { perror("SYSERR: malloc failure"); abort(); } } while(0) + +#define RECREATE(result,type,number) do {\ + if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\ + { printf("SYSERR: realloc failure"); abort(); } } while(0) + diff --git a/src/common/version.h b/src/common/version.h new file mode 100644 index 0000000..e33e2b3 --- /dev/null +++ b/src/common/version.h @@ -0,0 +1,27 @@ +// $Id: version.h,v 1.2 2004/09/22 09:49:06 PoW Exp $ +#ifndef _VERSION_H_ +#define _VERSION_H_ + +#define ATHENA_MAJOR_VERSION 1 // Major Version +#define ATHENA_MINOR_VERSION 0 // Minor Version +#define ATHENA_REVISION 0 // Revision + +#define ATHENA_RELEASE_FLAG 1 // 1=Develop,0=Stable +#define ATHENA_OFFICIAL_FLAG 1 // 1=Mod,0=Official + +#define ATHENA_SERVER_LOGIN 1 // login server +#define ATHENA_SERVER_CHAR 2 // char server +#define ATHENA_SERVER_INTER 4 // inter server +#define ATHENA_SERVER_MAP 8 // map server + +// ATHENA_MOD_VERSIONはパッチ番号です。 +// これは無理に変えなくても気が向いたら変える程度の扱いで。 +// (毎回アップロードの度に変更するのも面倒と思われるし、そもそも +// この項目を参照する人がいるかどうかで疑問だから。) +// その程度の扱いなので、サーバーに問い合わせる側も、あくまで目安程度の扱いで +// あんまり信用しないこと。 +// 鯖snapshotの時や、大きな変更があった場合は設定してほしいです。 +// C言語の仕様上、最初に0を付けると8進数になるので間違えないで下さい。 +#define ATHENA_MOD_VERSION 1052 // mod version (patch No.) + +#endif |