diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..9368c14 --- /dev/null +++ b/client/Makefile @@ -0,0 +1,57 @@ + +PATH := $(DEVKITPPC)/bin:$(PATH) + +PREFIX ?= powerpc-eabi- +LD := $(PREFIX)ld +AS := $(PREFIX)as +CC := $(PREFIX)gcc +OBJDUMP ?= $(PREFIX)objdump +OBJCOPY ?= $(PREFIX)objcopy + +SFLAGS := -mgekko -mregnames + +# -O2: optimise lots +# -Wall: generate lots of warnings +# -x c: compile as C code +# -std=gnu99: use the C99 standard with GNU extensions +# -ffreestanding: we don't have libc; don't expect we do +# -mrvl: enable wii/gamecube compilation +# -mcpu=750: enable processor specific compilation +# -meabi: enable eabi specific compilation +# -mhard-float: enable hardware floating point instructions +# -fshort-wchar: use 16 bit whcar_t type in keeping with Wii executables +# -msdata-none: do not use r2 or r13 as small data areas +# -memb: enable embedded application specific compilation +# -ffunction-sections: split up functions so linker can garbage collect +# -fdata-sections: split up data so linker can garbage collect +CFLAGS := -O2 -Wall -x c -std=gnu99 \ + -ffreestanding \ + -mrvl -mcpu=750 -meabi -mhard-float -fshort-wchar \ + -msdata=none -memb -ffunction-sections -fdata-sections \ + -Wno-unknown-pragmas -Wno-strict-aliasing \ + +SRC := $(wildcard *.S) $(wildcard *.c) +OBJ := $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC))) + +all: ../installer/saviine532.h + +../installer/saviine%.h: saviine%.text.bin saviine%.magic.bin + xxd -i saviine$*.magic.bin | sed "s/unsigned/static const unsigned/g;s/ine$*/ine/g" > $@ + xxd -i saviine$*.text.bin | sed "s/unsigned/static const unsigned/g;s/ine$*/ine/g" >> $@ + +saviine%.text.bin: saviine%.elf + $(OBJCOPY) -j .text -O binary $< $@ +saviine%.magic.bin: saviine%.elf + $(OBJCOPY) -j .magic -O binary $< $@ + +saviine%.elf: saviine%.ld $(OBJ) + $(LD) -T $< $(OBJ) + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $+ +%.o: %.S + $(AS) $(SFLAGS) -o $@ $+ + +clean: + rm -f $(wildcard *.o) $(wildcard *.elf) $(wildcard ../installer/saviine532.h) + diff --git a/client/main.c b/client/main.c new file mode 100644 index 0000000..16dfe4c --- /dev/null +++ b/client/main.c @@ -0,0 +1,310 @@ +#include "main.h" +#include "../common/fs_defs.h" +#define DECL(res, name, ...) \ + extern res name(__VA_ARGS__); \ + res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".magicptr"))); \ + res my_ ## name(__VA_ARGS__) + +#define BYTE_LOG_STR 0xfb + + +extern FSStatus FSOpenDir(FSClient *pClient, FSCmdBlock *pCmd, const char *path, int *dh, FSRetFlag errHandling); +extern FSStatus FSReadDir(FSClient *pClient, FSCmdBlock *pCmd, int dh, FSDirEntry *dir_entry, FSRetFlag errHandling); +extern FSStatus FSChangeDir(FSClient *pClient, FSCmdBlock *pCmd, const char *path, FSRetFlag errHandling); +extern FSStatus FSCloseDir(FSClient *pClient, FSCmdBlock *pCmd, int dh, FSRetFlag errHandling); +extern FSStatus FSReadFile(FSClient *pClient, FSCmdBlock *pCmd, void *buffer, int size, int count, int fd, int flag, int error); +extern FSStatus FSSetPosFile(FSClient *pClient, FSCmdBlock *pCmd, int fd, int pos, int error); +extern FSStatus FSCloseFile (FSClient *pClient, FSCmdBlock *pCmd, int fd, int error); +extern FSStatus FSOpenFile(FSClient *pClient, FSCmdBlock *pCmd, char *path, const char *mode, int *handle, int error); + +DECL(int, FSAInit, void) { + if ((int)bss_ptr == 0x0a000000) { + bss_ptr = memalign(sizeof(struct bss_t), 0x40); + memset(bss_ptr, 0, sizeof(struct bss_t)); + } + return real_FSAInit(); +} +DECL(int, FSAShutdown, void) { + return real_FSAShutdown(); +} +DECL(int, FSAAddClient, void *r3) { + int res = real_FSAAddClient(r3); + + if ((int)bss_ptr != 0x0a000000 && res < MAX_CLIENT && res >= 0) { + cafiine_connect(&bss.socket_fsa[res]); + } + + return res; +} +DECL(int, FSADelClient, int client) { + if ((int)bss_ptr != 0x0a000000 && client < MAX_CLIENT && client >= 0) { + cafiine_disconnect(bss.socket_fsa[client]); + } + + return real_FSADelClient(client); +} +DECL(int, FSAOpenFile, int client, const char *path, const char *mode, int *handle) { + return real_FSAOpenFile(client, path, mode, handle); +} + +static int client_num_alloc(void *pClient) { + int i; + + for (i = 0; i < MAX_CLIENT; i++) + if (bss.pClient_fs[i] == 0) { + bss.pClient_fs[i] = pClient; + return i; + } + return -1; +} +static void clietn_num_free(int client) { + bss.pClient_fs[client] = 0; +} +static int client_num(void *pClient) { + int i; + + for (i = 0; i < MAX_CLIENT; i++) + if (bss.pClient_fs[i] == pClient) + return i; + return -1; +} + + +struct fs_async_t { + void (*callback)(int status, int command, void *request, void *response, void *context); + void *context; + void *queue; +}; + +#define DUMP_BLOCK_SIZE (0x200 * 100) +#define DUMP_BLOCK_SIZE_SLOW (0x20 * 100) +static int dump_dir(void *pClient,int client, void *pCmd, char *path, int error, int handle){ + int dir_handle = handle; + int my_handle = handle +1; + int ret = 0; + if ((ret = FSOpenDir(pClient, pCmd, path, &dir_handle, FS_RET_ALL_ERROR)) == FS_STATUS_OK) + { + char new_mode[2]; + new_mode[0] = 'r'; + new_mode[1] = '\0'; + + FSDirEntry dir_entry; + while (FSReadDir(pClient, pCmd, dir_handle, &dir_entry, FS_RET_ALL_ERROR) == FS_STATUS_OK) + { + char full_path[255]; + int i=0; + char *path_ptr = (char *)path; + while(*path_ptr) { + full_path[i++] = *path_ptr++; + } + full_path[i++] = '/'; + char *dir_name_ptr = (char *)dir_entry.name; + while(*dir_name_ptr) { + full_path[i++] = *dir_name_ptr++; + } + full_path[i++] = '\0'; + + log_string(bss.socket_fsa[client], full_path, BYTE_LOG_STR); + if((dir_entry.stat.flag&FS_STAT_FLAG_IS_DIRECTORY) == FS_STAT_FLAG_IS_DIRECTORY){ + char type[4]; + type[0] = 'd'; + type[1] = 'i'; + type[2] = 'r'; + type[3] = '\0'; + log_string(bss.socket_fsa[client], type, BYTE_LOG_STR); + dump_dir(pClient,client,pCmd,full_path,error,my_handle); + }else{ + char type[5]; + type[0] = 'f'; + type[1] = 'i'; + type[2] = 'l'; + type[3] = 'e'; + type[4] = '\0'; + log_string(bss.socket_fsa[client], type, BYTE_LOG_STR); + //DUMP + ret = FSOpenFile(pClient, pCmd, full_path, new_mode, &my_handle, error); + if (ret >= 0) { + int my_ret = 1; + log_string(bss.socket_fsa[client], full_path, BYTE_LOG_STR); + int size = (my_ret == 1 ? DUMP_BLOCK_SIZE : DUMP_BLOCK_SIZE_SLOW); + cafiine_send_handle(bss.socket_fsa[client], client, full_path, my_handle); + void* buffer = memalign(sizeof(char) * size, 0x40); + int ret2; + while ((ret2 = FSReadFile(pClient, pCmd, buffer, 1, size, my_handle, 0, error)) > 0) + cafiine_send_file(bss.socket_fsa[client], buffer, ret2, my_handle); + cafiine_fclose(bss.socket_fsa[client], &ret2, my_handle); + FSSetPosFile(pClient, pCmd, my_handle, 0, error); + free(buffer); + FSCloseFile(pClient, pCmd, my_handle, -1); + } + } + } + FSCloseDir(pClient, pCmd, dir_handle, FS_RET_NO_ERROR); + }else{ + /* + char error[3]; + error[0] = '-'; + error[1] = (ret*-1) + '0'; + error[2] = '\0'; */ + //log_string(bss.socket_fsa[client], foo, BYTE_LOG_STR); + return -1; + } + return 0; +} + +DECL(int, FSInit, void) { + if ((int)bss_ptr == 0x0a000000) { + bss_ptr = memalign(sizeof(struct bss_t), 0x40); + memset(bss_ptr, 0, sizeof(struct bss_t)); + } + return real_FSInit(); +} +DECL(int, FSShutdown, void) { + return real_FSShutdown(); +} +DECL(int, FSAddClientEx, void *r3, void *r4, void *r5) { + int res = real_FSAddClientEx(r3, r4, r5); + + if ((int)bss_ptr != 0x0a000000 && res >= 0) { + int client = client_num_alloc(r3); + if (client < MAX_CLIENT && client >= 0) { + cafiine_connect(&bss.socket_fs[client]); + } + } + return res; +} +DECL(int, FSDelClient, void *pClient) { + if ((int)bss_ptr != 0x0a000000) { + int client = client_num(pClient); + if (client < MAX_CLIENT && client >= 0) { + cafiine_disconnect(bss.socket_fs[client]); + clietn_num_free(client); + } + } + return real_FSDelClient(pClient); +} + +static void dump_saves(void *pClient, void *pCmd,int error, int client){ + int i = 0; + char save_path[255]; + char save_user[9]; + char save_base[11]; + char save_common[7]; + + save_base[i++] = '/'; + save_base[i++] = 'v'; + save_base[i++] = 'o'; + save_base[i++] = 'l'; + save_base[i++] = '/'; + save_base[i++] = 's'; + save_base[i++] = 'a'; + save_base[i++] = 'v'; + save_base[i++] = 'e'; + save_base[i++] = '/'; + save_base[i++] = '\0'; + i = 0; + + save_user[i++] = '8'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '0'; + save_user[i++] = '\0'; + + i = 0; + save_common[i++] = 'c'; + save_common[i++] = 'o'; + save_common[i++] = 'm'; + save_common[i++] = 'm'; + save_common[i++] = 'o'; + save_common[i++] = 'n'; + save_common[i++] = '\0'; + + i = 0; + char *save_base_ptr = (char *)save_base; + while(*save_base_ptr) { + save_path[i++] = *save_base_ptr++; + } + + int k = i; + char *save_user_ptr = (char *)save_user; + while(*save_user_ptr) { + save_path[i++] = *save_user_ptr++; + } + save_path[i++] = '\0'; + int id = 1; + do{ + //log_string(bss.socket_fsa[client], save_path, BYTE_LOG_STR); + if (dump_dir(pClient,client,pCmd,save_path,error,50) == 0);// id = 257; // break if successful + int first = id/16; + int seconds = id%16; + if(first <= 9) + save_path[16] = '0' + first; + else + save_path[16] = 'a' + (first - 10); + + if(seconds <= 9) + save_path[17] = '0' + seconds; + else + save_path[17] = 'a' + (seconds - 10); + + id++; + }while(id < 257); + + i = k; + + char *save_common_ptr = (char *)save_common; + while(*save_common_ptr) { + save_path[i++] = *save_common_ptr++; + } + save_path[i++] = '\0'; + + log_string(bss.socket_fsa[client], save_path, BYTE_LOG_STR); + dump_dir(pClient,client,pCmd,save_path,error,60); + + i = 0; + char info[6]; + info[i++] = 'd'; + info[i++] = 'o'; + info[i++] = 'n'; + info[i++] = 'e'; + info[i++] = '!'; + info[i++] = '\0'; + log_string(bss.socket_fsa[client], info, BYTE_LOG_STR); +} + +DECL(int, FSGetStat, void *pClient, void *pCmd, char *path, void *stats, int error) { + if ((int)bss_ptr != 0x0a000000) { + int client = client_num(pClient); + + if (client < MAX_CLIENT && client >= 0) { + if(bss.savesDumped == 0){ + dump_saves(pClient,pCmd,error,client); + bss.savesDumped = 2; + } + } + } + return real_FSGetStat(pClient, pCmd, path, stats, error); +} + +#define MAKE_MAGIC(x) { x, my_ ## x, &real_ ## x } + +struct magic_t { + const void *real; + const void *replacement; + const void *call; +} methods[] __attribute__((section(".magic"))) = { + MAKE_MAGIC(FSAInit), + MAKE_MAGIC(FSAShutdown), + MAKE_MAGIC(FSAAddClient), + MAKE_MAGIC(FSADelClient), + MAKE_MAGIC(FSAOpenFile), + MAKE_MAGIC(FSGetStat), + MAKE_MAGIC(FSInit), + MAKE_MAGIC(FSShutdown), + MAKE_MAGIC(FSAddClientEx), + MAKE_MAGIC(FSDelClient), +}; diff --git a/client/main.h b/client/main.h new file mode 100644 index 0000000..f21c115 --- /dev/null +++ b/client/main.h @@ -0,0 +1,67 @@ +/* string.h */ +#define NULL ((void *)0) + +void *memcpy(void *dst, const void *src, int bytes); +void *memset(void *dst, int val, int bytes); + +/* malloc.h */ +extern void *(* const MEMAllocFromDefaultHeapEx)(int size, int align); +extern void *(* const MEMFreeToDefaultHeap)(void *ptr); +#define memalign (*MEMAllocFromDefaultHeapEx) +#define free (*MEMFreeToDefaultHeap) +/* socket.h */ +#define AF_INET 2 +#define SOCK_STREAM 1 +#define IPPROTO_TCP 6 + + + +extern void socket_lib_init(); +extern int socket(int domain, int type, int protocol); +extern int socketclose(int socket); +extern int connect(int socket, void *addr, int addrlen); +extern int send(int socket, const void *buffer, int size, int flags); +extern int recv(int socket, void *buffer, int size, int flags); + +struct in_addr { + unsigned int s_addr; +}; +struct sockaddr_in { + short sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +/* OS stuff */ +extern const long long title_id; + +/* Forward declarations */ +#define MAX_CLIENT 32 +#define MASK_FD 0x0fff00ff + +struct bss_t { + int socket_fsa[MAX_CLIENT]; + void *pClient_fs[MAX_CLIENT]; + int socket_fs[MAX_CLIENT]; + char save_path[255]; + volatile int savesDumped; + volatile int lock; +}; + +#define bss_ptr (*(struct bss_t **)0x100000e4) +#define bss (*bss_ptr) + +void cafiine_connect(int *socket); +void cafiine_disconnect(int socket); +int cafiine_fopen(int socket, int *result, const char *path, const char *mode, int *handle); +void cafiine_send_handle(int sock, int client, const char *path, int handle); +void cafiine_send_file(int sock, char *file, int size, int fd); +int cafiine_fread(int socket, int *result, void *buffer, int size, int count, int fd); +int cafiine_fclose(int socket, int *result, int fd); +int cafiine_fsetpos(int socket, int *result, int fd, int set); +int cafiine_fgetpos(int socket, int *result, int fd, int *pos); +int cafiine_fstat(int sock, int *result, int fd, void *ptr); +int cafiine_feof(int sock, int *result, int fd); +void cafiine_send_ping(int sock, int val1, int val2); +void log_string(int sock, const char* str, char flag_byte); \ No newline at end of file diff --git a/client/saviine.c b/client/saviine.c new file mode 100644 index 0000000..ba9110b --- /dev/null +++ b/client/saviine.c @@ -0,0 +1,253 @@ +#include "main.h" + +static int recvwait(int sock, void *buffer, int len); +static int recvbyte(int sock); +static int sendwait(int sock, const void *buffer, int len); + +static int cafiine_handshake(int sock); + +#define CHECK_ERROR(cond) if (cond) { goto error; } + +#define BYTE_NORMAL 0xff +#define BYTE_SPECIAL 0xfe +//#define BYTE_OPEN 0x00 +//#define BYTE_READ 0x01 +#define BYTE_CLOSE 0x02 +//#define BYTE_OK 0x03 +//#define BYTE_SETPOS 0x04 +//#define BYTE_STATFILE 0x05 +//#define BYTE_EOF 0x06 +//#define BYTE_GETPOS 0x07 +//#define BYTE_REQUEST 0x08 +//#define BYTE_REQUEST_SLOW 0x09 +#define BYTE_HANDLE 0x0A +#define BYTE_DUMP 0x0B +#define BYTE_PING 0x0C + +#define BYTE_LOG_STR 0xfb + +void GX2WaitForVsync(void); + +void cafiine_connect(int *psock) { + extern unsigned int server_ip; + struct sockaddr_in addr; + int sock, ret; + + socket_lib_init(); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + CHECK_ERROR(sock == -1); + + addr.sin_family = AF_INET; + addr.sin_port = 7332; + addr.sin_addr.s_addr = server_ip; + + ret = connect(sock, (void *)&addr, sizeof(addr)); + CHECK_ERROR(ret < 0); + ret = cafiine_handshake(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_NORMAL); + + *psock = sock; + return; +error: + if (sock != -1) + socketclose(sock); + *psock = -1; + return; +} + +void cafiine_disconnect(int sock) { + CHECK_ERROR(sock == -1); + socketclose(sock); +error: + return; +} + +static int cafiine_handshake(int sock) { + int ret; + unsigned char buffer[16]; + + memcpy(buffer, &title_id, 16); + + ret = sendwait(sock, buffer, sizeof(buffer)); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + return ret; +error: + return ret; +} + + +void cafiine_send_handle(int sock, int client, const char *path, int handle) +{ + while (bss.lock) GX2WaitForVsync(); + bss.lock = 1; + + CHECK_ERROR(sock == -1); + + // create and send buffer with : [cmd id][handle][path length][path data ...] + { + int ret; + int len_path = 0; + while (path[len_path++]); + char buffer[1 + 4 + 4 + len_path]; + + buffer[0] = BYTE_HANDLE; + *(int *)(buffer + 1) = handle; + *(int *)(buffer + 5) = len_path; + for (ret = 0; ret < len_path; ret++) + buffer[9 + ret] = path[ret]; + + // send buffer, wait for reply + ret = sendwait(sock, buffer, 1 + 4 + 4 + len_path); + CHECK_ERROR(ret < 0); + + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret != BYTE_SPECIAL); + } + +error: + bss.lock = 0; + return; +} + +void cafiine_send_file(int sock, char *file, int size, int fd) { + while (bss.lock) GX2WaitForVsync(); + bss.lock = 1; + + CHECK_ERROR(sock == -1); + + int ret; + + // create and send buffer with : [cmd id][fd][size][buffer data ...] + { + char buffer[1 + 4 + 4 + size]; + + buffer[0] = BYTE_DUMP; + *(int *)(buffer + 1) = fd; + *(int *)(buffer + 5) = size; + for (ret = 0; ret < size; ret++) + buffer[9 + ret] = file[ret]; + + // send buffer, wait for reply + ret = sendwait(sock, buffer, 1 + 4 + 4 + size); + + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret != BYTE_SPECIAL); + } + +error: + bss.lock = 0; + return; +} + + + +int cafiine_fclose(int sock, int *result, int fd) { + while (bss.lock) GX2WaitForVsync(); + bss.lock = 1; + + CHECK_ERROR(sock == -1); + + int ret; + char buffer[1 + 4]; + buffer[0] = BYTE_CLOSE; + *(int *)(buffer + 1) = fd; + ret = sendwait(sock, buffer, 1 + 4); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_NORMAL); + ret = recvwait(sock, result, 4); + CHECK_ERROR(ret < 0); + + bss.lock = 0; + return 0; +error: + bss.lock = 0; + return -1; +} + +void cafiine_send_ping(int sock, int val1, int val2) { + while (bss.lock) GX2WaitForVsync(); + bss.lock = 1; + + int ret; + char buffer[1 + 4 + 4]; + buffer[0] = BYTE_PING; + *(int *)(buffer + 1) = val1; + *(int *)(buffer + 5) = val2; + + ret = sendwait(sock, buffer, 1 + 4 + 4); + CHECK_ERROR(ret < 0); + + error: + bss.lock = 0; + return; +} + +static int recvwait(int sock, void *buffer, int len) { + int ret; + while (len > 0) { + ret = recv(sock, buffer, len, 0); + CHECK_ERROR(ret < 0); + len -= ret; + buffer += ret; + } + return 0; +error: + return ret; +} + +static int recvbyte(int sock) { + unsigned char buffer[1]; + int ret; + + ret = recvwait(sock, buffer, 1); + if (ret < 0) return ret; + return buffer[0]; +} + +static int sendwait(int sock, const void *buffer, int len) { + int ret; + while (len > 0) { + ret = send(sock, buffer, len, 0); + CHECK_ERROR(ret < 0); + len -= ret; + buffer += ret; + } + return 0; +error: + return ret; +} + +void log_string(int sock, const char* str, char flag_byte) { + if(sock == -1) { + return; + } + while (bss.lock) GX2WaitForVsync(); + bss.lock = 1; + + int i; + int len_str = 0; + while (str[len_str++]); + + // + { + char buffer[1 + 4 + len_str]; + buffer[0] = flag_byte; + *(int *)(buffer + 1) = len_str; + for (i = 0; i < len_str; i++) + buffer[5 + i] = str[i]; + + buffer[5 + i] = 0; + + sendwait(sock, buffer, 1 + 4 + len_str); + } + + bss.lock = 0; +} diff --git a/client/saviine532.ld b/client/saviine532.ld new file mode 100644 index 0000000..218ae3b --- /dev/null +++ b/client/saviine532.ld @@ -0,0 +1,70 @@ +OUTPUT(cafiine532.elf); + +SECTIONS { + .text 0x011de000 : { + server_ip = .; + . = . + 4; + *(.text._start); + *(.text*); + *(.magicptr*); + } + .magic : { + *(.magic*); + } + /DISCARD/ : { + *(*); + } +} + +/* FSA methods */ +PROVIDE(FSAInit = 0x10608ac); +PROVIDE(FSAShutdown = 0x1060974); +PROVIDE(FSAAddClient = 0x106546c); +PROVIDE(FSADelClient = 0x1060aa4); +PROVIDE(FSAOpenFile = 0x10621f8); + +/* FS methods */ +PROVIDE(FSInit = 0x10683c8); +PROVIDE(FSShutdown = 0x1068538); +PROVIDE(FSAddClientEx = 0x10685fc); +PROVIDE(FSDelClient = 0x1068a08); +PROVIDE(FSOpenFile = 0x106ef7c); +PROVIDE(FSCloseFile = 0x106f088); +PROVIDE(FSReadFile = 0x106f108); +PROVIDE(FSReadFileWithPos = 0x106f194); +PROVIDE(FSGetPosFile = 0x106f4c0); +PROVIDE(FSSetPosFile = 0x106f530); +PROVIDE(FSGetStatFile = 0x106f5a0); +PROVIDE(FSIsEof = 0x106f610); + +/* */ +PROVIDE(FSGetStat = 0x0106fdc8); +PROVIDE(FSGetStatAsync = 0x0106bff4); +PROVIDE(FSOpenFileAsync = 0x0106a434); + +PROVIDE(FSOpenDir = 0x0106f690); +PROVIDE(FSReadDir = 0x0106f780); +PROVIDE(FSCloseDir = 0x0106f700); +PROVIDE(FSChangeDir = 0x0106eefc); +PROVIDE(FSCloseDir = 0x0106f700); + + +/* GX2 methods */ +PROVIDE(GX2WaitForVsync = 0x1151964); + +/* Socket methods */ +PROVIDE(socket_lib_init = 0x10c02f4); +PROVIDE(socket = 0x10c21c8); +PROVIDE(socketclose = 0x10c2314); +PROVIDE(connect = 0x10c0828); +PROVIDE(send = 0x10c16ac); +PROVIDE(recv = 0x10c0aec); + +/* Standard library methods */ +PROVIDE(memcpy = 0x1035a68); +PROVIDE(memset = 0x1035a54); +PROVIDE(MEMAllocFromDefaultHeapEx = 0x1004e9c0); +PROVIDE(MEMFreeToDefaultHeap = 0x100b487c); + +/* OS data */ +PROVIDE(title_id = 0x100136D0); \ No newline at end of file diff --git a/common/common.h b/common/common.h new file mode 100644 index 0000000..4327bbf --- /dev/null +++ b/common/common.h @@ -0,0 +1,45 @@ +#ifndef COMMON_H +#define COMMON_H + +/* DATA_ADDRESS : address where flags start */ +#define DATA_ADDR ((void *)0x011e3800) +#define BOUNCE_FLAG_ADDR (DATA_ADDR - 0x04) // bounce flag +#define IS_ACTIVE_ADDR (DATA_ADDR - 0x08) // is replacement active +#define RPL_REPLACE_ADDR (DATA_ADDR - 0x0C) // is it a new rpl to add +#define RPL_ENTRY_INDEX_ADDR (DATA_ADDR - 0x10) // entry index of the rpx in our table + +/* RPX Address : where the rpx is copied or retrieve, depends if we dump or replace */ +/* Note : from phys 0x30789C5D to 0x31E20000, memory seems empty (space reserved for root.rpx) which let us approximatly 22.5mB of memory free to put the rpx and additional rpls */ +#define MEM_BASE ((void*)0xC0800000) +#define MEM_SIZE ((void*)(MEM_BASE - 0x04)) +#define MEM_OFFSET ((void*)(MEM_BASE - 0x08)) +#define MEM_PART ((void*)(MEM_BASE - 0x0C)) +#define RPX_NAME ((void*)(MEM_BASE - 0x10)) +#define RPX_NAME_PENDING ((void*)(MEM_BASE - 0x14)) +#define GAME_DIR_NAME ((void*)(MEM_BASE - 0x100)) + +/* RPX_RPL_ARRAY contains an array of multiple rpl/rpl structures: */ +/* Note : The first entry is always the one referencing the rpx (cf. struct s_rpx_rpl) */ +#define RPX_RPL_ARRAY ((void*)0xC07A0000) +#define RPX_RPL_ENTRY_COUNT ((void*)(RPX_RPL_ARRAY - 0x04)) + +/* RPX Name : from which app/game, our rpx is launched */ +#define RPX_CHECK_NAME 0x63726F73 // 0xEFE00000 contains the rpx name, 0x63726F73 => cros (for smash brox : cross_f.rpx) + +/* Union for rpx name */ +typedef union uRpxName { + int name_full; + char name[4]; +} uRpxName; + +/* Struct used to organize rpx/rpl data in memory */ +typedef struct s_rpx_rpl +{ + int address; + int size; + int offset; + char name[64]; // TODO: maybe set the exact same size than dir_entry->name +} s_rpx_rpl; + +#endif /* COMMON_H */ + diff --git a/common/fs_defs.h b/common/fs_defs.h new file mode 100644 index 0000000..95b3180 --- /dev/null +++ b/common/fs_defs.h @@ -0,0 +1,79 @@ +#ifndef FS_DEFS_H +#define FS_DEFS_H + +#include "../common/types.h" + +/* FS defines and types */ +#define FS_MAX_LOCALPATH_SIZE 511 +#define FS_MAX_MOUNTPATH_SIZE 128 +#define FS_MAX_FULLPATH_SIZE (FS_MAX_LOCALPATH_SIZE + FS_MAX_MOUNTPATH_SIZE) +#define FS_MAX_ARGPATH_SIZE FS_MAX_FULLPATH_SIZE + +#define FS_STATUS_OK 0 +#define FS_RET_UNSUPPORTED_CMD 0x0400 +#define FS_RET_NO_ERROR 0x0000 +#define FS_RET_ALL_ERROR (uint)(-1) + +/* directory entry stat flag */ +#define FS_STAT_ATTRIBUTES_SIZE (48) /* size of FS-specific attributes field */ +#define FS_STAT_FLAG_IS_DIRECTORY 0x80000000 /* entry is directory */ + +/* max length of file/dir name */ +#define FS_MAX_ENTNAME_SIZE 256 + +/* typedef FSStatus, FSRetFlag*/ +typedef int FSStatus; +typedef uint FSRetFlag; +typedef uint FSFlag; + +/* FS Mount */ +typedef enum +{ + FS_SOURCETYPE_EXTERNAL = 0, // Manual mounted external device + FS_SOURCETYPE_HFIO, // Host file IO + FS_SOURCETYPE_MAX +} FSSourceType; + +typedef struct +{ + FSSourceType type; + char path[FS_MAX_ARGPATH_SIZE]; +} FSMountSource; + +/* FS Client context buffer */ +typedef struct +{ + uint8_t buffer[5888]; +} FSClient; + +/* FS command block buffer */ +typedef struct +{ + uint8_t buffer[2688]; +} FSCmdBlock; + +/* File/Dir status */ +typedef struct +{ + uint flag; + uint permission; + uint owner_id; + uint group_id; + uint size; + uint alloc_size; + uint64_t quota_size; + uint ent_id; + uint64_t ctime; + uint64_t mtime; + uint8_t attributes[FS_STAT_ATTRIBUTES_SIZE]; +} __attribute__((packed)) FSStat; + +/* Directory entry */ +typedef struct +{ + FSStat stat; + char name[FS_MAX_ENTNAME_SIZE]; +} FSDirEntry; + +#endif /* FS_DEFS_H */ + diff --git a/common/types.h b/common/types.h new file mode 100644 index 0000000..eefac9b --- /dev/null +++ b/common/types.h @@ -0,0 +1,22 @@ +#ifndef TYPES_H +#define TYPES_H + +/* Define base types */ +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef unsigned int uint32_t; +typedef unsigned int uint; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef char int8_t; + +typedef _Bool bool; +#define true 1 +#define false 0 +#define null 0 + + +#endif /* TYPES_H */ + diff --git a/installer/Makefile b/installer/Makefile new file mode 100644 index 0000000..31acf83 --- /dev/null +++ b/installer/Makefile @@ -0,0 +1,29 @@ +CC=powerpc-eabi-gcc +CFLAGS=-std=gnu99 -nostdinc -fno-builtin -c +LD=powerpc-eabi-ld +LDFLAGS=-Ttext 1800000 --oformat binary +project := . +root:=$(CURDIR) +build := $(root)/bin +libs := $(root)/../../libwiiu/bin +www :=$(root)/../../www +framework:=$(root)/../../framework + +all: clean setup client main532 + +setup: + mkdir -p $(root)/bin/ + +client: + cd ../client/ && make + +main532: + $(CC) $(CFLAGS) -DVER=532 $(project)/saviine.c + #-Wa,-a,-ad + cp -r $(root)/*.o $(build) + rm $(root)/*.o + #$(LD) $(LDFLAGS) -o $(build)/code532.bin $(build)/saviine.o $(libs)/532/*.o `find $(build) -name "*.o" ! -name "saviine.o"` + $(LD) $(LDFLAGS) -o $(build)/code532.bin $(build)/saviine.o `find $(build) -name "*.o" ! -name "saviine.o"` + +clean: + rm -rf $(build)/* diff --git a/installer/bin/code532.bin b/installer/bin/code532.bin new file mode 100644 index 0000000..b4771ff Binary files /dev/null and b/installer/bin/code532.bin differ diff --git a/installer/bin/saviine.o b/installer/bin/saviine.o new file mode 100644 index 0000000..de18b79 Binary files /dev/null and b/installer/bin/saviine.o differ diff --git a/installer/saviine.c b/installer/saviine.c new file mode 100644 index 0000000..71b4c76 --- /dev/null +++ b/installer/saviine.c @@ -0,0 +1,247 @@ +#include "../../libwiiu/src/coreinit.h" +#include "../../libwiiu/src/socket.h" +#include "../../libwiiu/src/vpad.h" + +#define assert(x) \ + do { \ + if (!(x)) \ + OSFatal("Assertion failed " #x ".\n"); \ + } while (0) + +#if VER == 532 + #include "saviine532.h" + + #define socket_lib_finish ((void (*)(void))0x10c0404) + + /* Where to install the saviine handler. */ + #define INSTALL_ADDR ((void *)0x011de000) + #define KERN_ADDRESS_TBL 0xFFEAAA10 +#endif + +void kern_write(void *addr, uint32_t value); +#define DEFAULT_SERVER_IP 0xC0A8010A +#define PRINT_TEXT1(x, y, str) { OSScreenPutFontEx(1, x, y, str); } +#define PRINT_TEXT2(x, y, _fmt, ...) { __os_snprintf(msg, 80, _fmt, __VA_ARGS__); OSScreenPutFontEx(1, x, y, msg); } +#define BTN_PRESSED (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN) + +typedef union u_serv_ip +{ + uint8_t digit[4]; + uint32_t full; +} u_serv_ip; + +void start() { + /* Load a good stack */ + asm( + "lis %r1, 0x1ab5 ;" + "ori %r1, %r1, 0xd138 ;" + ); + + /* Get a handle to coreinit.rpl. */ + unsigned int coreinit_handle; + OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); + + /* Load a few useful symbols. */ + void (*_Exit)(void) __attribute__ ((noreturn)); + void (*DCFlushRange)(const void *, int); + void *(*OSEffectiveToPhysical)(const void *); + + OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); + OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); + OSDynLoad_FindExport(coreinit_handle, 0, "OSEffectiveToPhysical", &OSEffectiveToPhysical); + + assert(_Exit); + assert(DCFlushRange); + assert(OSEffectiveToPhysical); + + /* Exploit proper begins here. */ + if (OSEffectiveToPhysical((void *)0xa0000000) != (void *)0x31000000) { + OSFatal("no ksploit"); + } else { + /* Second run. */ + + /* ****************************************************************** */ + /* IP Settings */ + /* ****************************************************************** */ + + // Set server ip + u_serv_ip ip; + ip.full = DEFAULT_SERVER_IP; + + // Prepare screen + void (*OSScreenInit)(); + unsigned int (*OSScreenGetBufferSizeEx)(unsigned int bufferNum); + unsigned int (*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); + unsigned int (*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); + unsigned int (*OSScreenFlipBuffersEx)(unsigned int bufferNum); + unsigned int (*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, void * buffer); + + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenInit", &OSScreenInit); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); + + int screen_buf0_size = 0; + int screen_buf1_size = 0; + uint32_t screen_color = 0; // (r << 24) | (g << 16) | (b << 8) | a; + char msg[80]; + + // Init screen + OSScreenInit(); + + // Set screens buffers + screen_buf0_size = OSScreenGetBufferSizeEx(0); + screen_buf1_size = OSScreenGetBufferSizeEx(1); + + OSScreenSetBufferEx(0, (void *)0xF4000000); + OSScreenSetBufferEx(1, (void *)0xF4000000 + screen_buf0_size); + + // Clear screens + OSScreenClearBufferEx(0, screen_color); + OSScreenClearBufferEx(1, screen_color); + + // Flush the cache + DCFlushRange((void *)0xF4000000, screen_buf0_size); + DCFlushRange((void *)0xF4000000 + screen_buf0_size, screen_buf1_size); + + // Flip buffers + OSScreenFlipBuffersEx(0); + OSScreenFlipBuffersEx(1); + + // Prepare vpad + unsigned int vpad_handle; + int (*VPADRead)(int controller, VPADData *buffer, unsigned int num, int *error); + OSDynLoad_Acquire("vpad.rpl", &vpad_handle); + OSDynLoad_FindExport(vpad_handle, 0, "VPADRead", &VPADRead); + + // Set server ip with buttons + uint8_t sel_ip = 3; + int error; + uint8_t button_pressed = 1; + VPADData vpad_data; + VPADRead(0, &vpad_data, 1, &error); //Read initial vpad status + while (1) + { + // Refresh screen if needed + if (button_pressed) { OSScreenFlipBuffersEx(1); OSScreenClearBufferEx(1, 0); } + + // Print message + PRINT_TEXT1(18, 1, "-- SAVIINE (a cafiine mod) --"); + PRINT_TEXT2(0, 5, "%s : %3d.%3d.%3d.%3d", "1. Server IP", ip.digit[0], ip.digit[1], ip.digit[2], ip.digit[3]); + PRINT_TEXT1(0, 6, "2. Press A to install saviine"); + PRINT_TEXT1(42, 17, "home button to exit ..."); + + // Print ip digit selector + uint8_t x_shift = 15 + 4 * sel_ip; + PRINT_TEXT1(x_shift, 4, "vvv"); + + // Read vpad + VPADRead(0, &vpad_data, 1, &error); + + // Update screen + if (button_pressed) + { + OSScreenFlipBuffersEx(1); + OSScreenClearBufferEx(1, 0); + } + // Check for buttons + else + { + // Home Button + if (vpad_data.btn_hold & BUTTON_HOME) + goto quit; + + // A Button + if (vpad_data.btn_hold & BUTTON_A) + break; + + // Left/Right Buttons + if (vpad_data.btn_hold & BUTTON_LEFT ) sel_ip = !sel_ip ? sel_ip = 3 : --sel_ip; + if (vpad_data.btn_hold & BUTTON_RIGHT) sel_ip = ++sel_ip % 4; + + // Up/Down Buttons + if (vpad_data.btn_hold & BUTTON_UP ) ip.digit[sel_ip] = ++ip.digit[sel_ip]; + if (vpad_data.btn_hold & BUTTON_DOWN) ip.digit[sel_ip] = --ip.digit[sel_ip]; + } + + // Button pressed ? + button_pressed = (vpad_data.btn_hold & BTN_PRESSED) ? 1 : 0; + } + + /* ****************************************************************** */ + /* Saviine installation */ + /* ****************************************************************** */ + + /* Copy in our resident cafiine client. */ + unsigned int len = sizeof(cafiine_text_bin); + unsigned char *loc = (unsigned char *)((char *)INSTALL_ADDR + 0xa0000000); + + while (len--) { + loc[len] = cafiine_text_bin[len]; + } + + /* server IP address */ + ((unsigned int *)loc)[0] = ip.full; //PC_IP; + + DCFlushRange(loc, sizeof(cafiine_text_bin)); + + struct magic_t { + void *real; + void *replacement; + void *call; + } *magic = (struct magic_t *)cafiine_magic_bin; + len = sizeof(cafiine_magic_bin) / sizeof(struct magic_t); + + int *space = (int *)(loc + sizeof(cafiine_text_bin)); + /* Patch branches to it. */ + while (len--) { + *(int *)(0xa0000000 | (int)magic[len].call) = (int)space - 0xa0000000; + + *space = *(int *)(0xa0000000 | (int)magic[len].real); + space++; + + *space = 0x48000002 | (((int)magic[len].real + 4) & 0x03fffffc); + space++; + DCFlushRange(space - 2, 8); + + *(int *)(0xa0000000 | (int)magic[len].real) = 0x48000002 | ((int)magic[len].replacement & 0x03fffffc); + DCFlushRange((int *)(0xa0000000 | (int)magic[len].real), 4); + } + + unsigned int *socket_finish = (unsigned int *)((char *)socket_lib_finish + 0xa0000000); + socket_finish[0] = 0x38600000; + socket_finish[1] = 0x4e800020; + + /* The fix for Splatoon and such */ + kern_write(KERN_ADDRESS_TBL + (0x12 * 4), 0x00000000); + kern_write(KERN_ADDRESS_TBL + (0x13 * 4), 0x14000000); + } + +quit: + _Exit(); +} + +/* Write a 32-bit word with kernel permissions */ +void kern_write(void *addr, uint32_t value) +{ + asm( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + :"r"(addr), "r"(value) + :"memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} diff --git a/installer/saviine532.h b/installer/saviine532.h new file mode 100644 index 0000000..f75c14f --- /dev/null +++ b/installer/saviine532.h @@ -0,0 +1,415 @@ +static const unsigned char cafiine_magic_bin[] = { + 0x01, 0x06, 0x08, 0xac, 0x01, 0x1d, 0xe8, 0x04, 0x01, 0x1d, 0xf2, 0x98, + 0x01, 0x06, 0x09, 0x74, 0x01, 0x1d, 0xe7, 0xd4, 0x01, 0x1d, 0xf2, 0x8c, + 0x01, 0x06, 0x54, 0x6c, 0x01, 0x1d, 0xe9, 0x24, 0x01, 0x1d, 0xf2, 0xa0, + 0x01, 0x06, 0x0a, 0xa4, 0x01, 0x1d, 0xea, 0x44, 0x01, 0x1d, 0xf2, 0xa8, + 0x01, 0x06, 0x21, 0xf8, 0x01, 0x1d, 0xe7, 0xe4, 0x01, 0x1d, 0xf2, 0x90, + 0x01, 0x06, 0xfd, 0xc8, 0x01, 0x1d, 0xf1, 0x70, 0x01, 0x1d, 0xf2, 0xb0, + 0x01, 0x06, 0x83, 0xc8, 0x01, 0x1d, 0xe8, 0x94, 0x01, 0x1d, 0xf2, 0x9c, + 0x01, 0x06, 0x85, 0x38, 0x01, 0x1d, 0xe7, 0xf4, 0x01, 0x1d, 0xf2, 0x94, + 0x01, 0x06, 0x85, 0xfc, 0x01, 0x1d, 0xe9, 0x8c, 0x01, 0x1d, 0xf2, 0xa4, + 0x01, 0x06, 0x8a, 0x08, 0x01, 0x1d, 0xea, 0xa8, 0x01, 0x1d, 0xf2, 0xac +}; +static const unsigned int cafiine_magic_bin_len = 120; +static const unsigned char cafiine_text_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0xe8, 0x7c, 0x08, 0x02, 0xa6, + 0x93, 0xe1, 0x00, 0x14, 0x7c, 0xbf, 0x2b, 0x79, 0x93, 0xa1, 0x00, 0x0c, + 0x7c, 0x7d, 0x1b, 0x78, 0x93, 0xc1, 0x00, 0x10, 0x7c, 0x9e, 0x23, 0x78, + 0x90, 0x01, 0x00, 0x1c, 0x41, 0xa1, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x4c, + 0x40, 0x9d, 0x00, 0x48, 0x7f, 0xc4, 0xf3, 0x78, 0x7f, 0xe5, 0xfb, 0x78, + 0x7f, 0xa3, 0xeb, 0x78, 0x38, 0xc0, 0x00, 0x00, 0x4b, 0xee, 0x36, 0x69, + 0x2c, 0x03, 0x00, 0x00, 0x7f, 0xe3, 0xf8, 0x50, 0x7f, 0xde, 0x1a, 0x14, + 0x2f, 0x9f, 0x00, 0x00, 0x40, 0x80, 0xff, 0xd8, 0x80, 0x01, 0x00, 0x1c, + 0x83, 0xa1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x10, + 0x83, 0xe1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x18, 0x4e, 0x80, 0x00, 0x20, + 0x80, 0x01, 0x00, 0x1c, 0x38, 0x60, 0x00, 0x00, 0x83, 0xa1, 0x00, 0x0c, + 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x10, 0x83, 0xe1, 0x00, 0x14, + 0x38, 0x21, 0x00, 0x18, 0x4e, 0x80, 0x00, 0x20, 0x94, 0x21, 0xff, 0xe8, + 0x7c, 0x08, 0x02, 0xa6, 0x93, 0xe1, 0x00, 0x14, 0x7c, 0xbf, 0x2b, 0x79, + 0x93, 0xa1, 0x00, 0x0c, 0x7c, 0x7d, 0x1b, 0x78, 0x93, 0xc1, 0x00, 0x10, + 0x7c, 0x9e, 0x23, 0x78, 0x90, 0x01, 0x00, 0x1c, 0x41, 0xa1, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x4c, 0x40, 0x9d, 0x00, 0x48, 0x7f, 0xc4, 0xf3, 0x78, + 0x7f, 0xe5, 0xfb, 0x78, 0x7f, 0xa3, 0xeb, 0x78, 0x38, 0xc0, 0x00, 0x00, + 0x4b, 0xee, 0x2a, 0x15, 0x2c, 0x03, 0x00, 0x00, 0x7f, 0xe3, 0xf8, 0x50, + 0x7f, 0xde, 0x1a, 0x14, 0x2f, 0x9f, 0x00, 0x00, 0x40, 0x80, 0xff, 0xd8, + 0x80, 0x01, 0x00, 0x1c, 0x83, 0xa1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x83, 0xc1, 0x00, 0x10, 0x83, 0xe1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x18, + 0x4e, 0x80, 0x00, 0x20, 0x80, 0x01, 0x00, 0x1c, 0x38, 0x60, 0x00, 0x00, + 0x83, 0xa1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x10, + 0x83, 0xe1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x18, 0x4e, 0x80, 0x00, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xc0, 0x93, 0xc1, 0x00, 0x38, + 0x7c, 0x7e, 0x1b, 0x78, 0x90, 0x01, 0x00, 0x44, 0x93, 0xe1, 0x00, 0x3c, + 0x4b, 0xee, 0x21, 0xb1, 0x38, 0x60, 0x00, 0x02, 0x38, 0x80, 0x00, 0x01, + 0x38, 0xa0, 0x00, 0x06, 0x4b, 0xee, 0x40, 0x75, 0x2f, 0x83, 0xff, 0xff, + 0x7c, 0x7f, 0x1b, 0x78, 0x41, 0x9e, 0x00, 0xa8, 0x3d, 0x20, 0x01, 0x1e, + 0x39, 0x40, 0x00, 0x02, 0x81, 0x29, 0xe0, 0x00, 0x38, 0x81, 0x00, 0x18, + 0xb1, 0x41, 0x00, 0x18, 0x38, 0xa0, 0x00, 0x10, 0x39, 0x40, 0x1c, 0xa4, + 0x91, 0x21, 0x00, 0x1c, 0xb1, 0x41, 0x00, 0x1a, 0x4b, 0xee, 0x26, 0xa1, + 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x70, 0x3c, 0x80, 0x10, 0x01, + 0x38, 0xa0, 0x00, 0x10, 0x38, 0x84, 0x36, 0xd0, 0x38, 0x61, 0x00, 0x08, + 0x4b, 0xe5, 0x78, 0xc5, 0x7f, 0xe3, 0xfb, 0x78, 0x38, 0x81, 0x00, 0x08, + 0x38, 0xa0, 0x00, 0x10, 0x4b, 0xff, 0xfe, 0x51, 0x2f, 0x83, 0x00, 0x00, + 0x41, 0x9c, 0x00, 0x44, 0x7f, 0xe3, 0xfb, 0x78, 0x38, 0x81, 0x00, 0x28, + 0x38, 0xa0, 0x00, 0x01, 0x4b, 0xff, 0xfe, 0xcd, 0x2f, 0x83, 0x00, 0x00, + 0x41, 0x9c, 0x00, 0x2c, 0x89, 0x21, 0x00, 0x28, 0x2b, 0x89, 0x00, 0xff, + 0x41, 0x9e, 0x00, 0x20, 0x80, 0x01, 0x00, 0x44, 0x93, 0xfe, 0x00, 0x00, + 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x38, 0x83, 0xe1, 0x00, 0x3c, + 0x38, 0x21, 0x00, 0x40, 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xe3, 0xfb, 0x78, + 0x4b, 0xee, 0x41, 0x11, 0x80, 0x01, 0x00, 0x44, 0x39, 0x20, 0xff, 0xff, + 0x91, 0x3e, 0x00, 0x00, 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x38, + 0x83, 0xe1, 0x00, 0x3c, 0x38, 0x21, 0x00, 0x40, 0x4e, 0x80, 0x00, 0x20, + 0x2f, 0x83, 0xff, 0xff, 0x4d, 0x9e, 0x00, 0x20, 0x4b, 0xee, 0x40, 0xe4, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xd0, 0x93, 0xc1, 0x00, 0x28, + 0x3f, 0xc0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x34, 0x63, 0xde, 0x00, 0xe4, + 0x93, 0x61, 0x00, 0x1c, 0x7c, 0xdb, 0x33, 0x78, 0x81, 0x3e, 0x00, 0x00, + 0x93, 0x81, 0x00, 0x20, 0x7c, 0x7c, 0x1b, 0x78, 0x81, 0x49, 0x02, 0x84, + 0x93, 0xa1, 0x00, 0x24, 0x7c, 0xbd, 0x2b, 0x78, 0x2f, 0x8a, 0x00, 0x00, + 0x93, 0xe1, 0x00, 0x2c, 0x7c, 0x3f, 0x0b, 0x78, 0x41, 0x9e, 0x00, 0x18, + 0x4b, 0xf7, 0x36, 0xe9, 0x81, 0x3e, 0x00, 0x00, 0x81, 0x49, 0x02, 0x84, + 0x2f, 0x8a, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, 0x2f, 0x9c, 0xff, 0xff, + 0x39, 0x40, 0x00, 0x01, 0x91, 0x49, 0x02, 0x84, 0x41, 0x9e, 0x00, 0xa4, + 0x39, 0x1d, 0xff, 0xff, 0x39, 0x40, 0x00, 0x00, 0x48, 0x00, 0x00, 0x08, + 0x7d, 0x2a, 0x4b, 0x78, 0x8c, 0xe8, 0x00, 0x01, 0x39, 0x2a, 0x00, 0x01, + 0x2f, 0x87, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, 0x39, 0x0a, 0x00, 0x19, + 0x80, 0xe1, 0x00, 0x00, 0x55, 0x08, 0x00, 0x36, 0x7d, 0x26, 0x4b, 0x79, + 0x7d, 0x08, 0x00, 0xd0, 0x7c, 0x3e, 0x0b, 0x78, 0x7c, 0xe1, 0x41, 0x6e, + 0x39, 0x00, 0x00, 0x0a, 0x7c, 0xc9, 0x03, 0xa6, 0x38, 0xaa, 0x00, 0x0a, + 0x38, 0x81, 0x00, 0x08, 0x99, 0x01, 0x00, 0x08, 0x91, 0x24, 0x00, 0x05, + 0x39, 0x20, 0x00, 0x00, 0x93, 0x64, 0x00, 0x01, 0x40, 0x81, 0x00, 0x80, + 0x7c, 0xfd, 0x48, 0xae, 0x7d, 0x04, 0x4a, 0x14, 0x39, 0x29, 0x00, 0x01, + 0x98, 0xe8, 0x00, 0x09, 0x42, 0x00, 0xff, 0xf0, 0x7f, 0x83, 0xe3, 0x78, + 0x4b, 0xff, 0xfc, 0xed, 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x14, + 0x7f, 0x83, 0xe3, 0x78, 0x38, 0x9f, 0x00, 0x08, 0x38, 0xa0, 0x00, 0x01, + 0x4b, 0xff, 0xfd, 0x69, 0x81, 0x21, 0x00, 0x00, 0x91, 0x3e, 0x00, 0x00, + 0x7f, 0xc1, 0xf3, 0x78, 0x39, 0x7f, 0x00, 0x30, 0x80, 0x0b, 0x00, 0x04, + 0x3d, 0x20, 0x10, 0x00, 0x83, 0xeb, 0xff, 0xfc, 0x7c, 0x08, 0x03, 0xa6, + 0x61, 0x29, 0x00, 0xe4, 0x81, 0x29, 0x00, 0x00, 0x39, 0x40, 0x00, 0x00, + 0x83, 0x6b, 0xff, 0xec, 0x91, 0x49, 0x02, 0x84, 0x83, 0x8b, 0xff, 0xf0, + 0x83, 0xab, 0xff, 0xf4, 0x83, 0xcb, 0xff, 0xf8, 0x7d, 0x61, 0x5b, 0x78, + 0x4e, 0x80, 0x00, 0x20, 0x39, 0x40, 0x00, 0x01, 0x7d, 0x49, 0x03, 0xa6, + 0x4b, 0xff, 0xff, 0x7c, 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xd0, + 0x93, 0xc1, 0x00, 0x28, 0x3f, 0xc0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x34, + 0x63, 0xde, 0x00, 0xe4, 0x93, 0x41, 0x00, 0x18, 0x7c, 0xda, 0x33, 0x78, + 0x81, 0x3e, 0x00, 0x00, 0x93, 0x61, 0x00, 0x1c, 0x7c, 0x7b, 0x1b, 0x78, + 0x81, 0x49, 0x02, 0x84, 0x93, 0x81, 0x00, 0x20, 0x7c, 0xbc, 0x2b, 0x78, + 0x2f, 0x8a, 0x00, 0x00, 0x93, 0xa1, 0x00, 0x24, 0x93, 0xe1, 0x00, 0x2c, + 0x7c, 0x9d, 0x23, 0x78, 0x7c, 0x3f, 0x0b, 0x78, 0x41, 0x9e, 0x00, 0x18, + 0x4b, 0xf7, 0x35, 0x8d, 0x81, 0x3e, 0x00, 0x00, 0x81, 0x49, 0x02, 0x84, + 0x2f, 0x8a, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, 0x2f, 0x9b, 0xff, 0xff, + 0x39, 0x40, 0x00, 0x01, 0x91, 0x49, 0x02, 0x84, 0x41, 0x9e, 0x00, 0x7c, + 0x39, 0x3c, 0x00, 0x18, 0x81, 0x41, 0x00, 0x00, 0x55, 0x29, 0x00, 0x36, + 0x2f, 0x9c, 0x00, 0x00, 0x7d, 0x29, 0x00, 0xd0, 0x7c, 0x3e, 0x0b, 0x78, + 0x7d, 0x41, 0x49, 0x6e, 0x39, 0x20, 0x00, 0x0b, 0x7f, 0x89, 0x03, 0xa6, + 0x38, 0xbc, 0x00, 0x09, 0x38, 0x81, 0x00, 0x08, 0x99, 0x21, 0x00, 0x08, + 0x93, 0x44, 0x00, 0x01, 0x39, 0x20, 0x00, 0x00, 0x93, 0x84, 0x00, 0x05, + 0x40, 0x9d, 0x00, 0x18, 0x7d, 0x1d, 0x48, 0xae, 0x7d, 0x44, 0x4a, 0x14, + 0x39, 0x29, 0x00, 0x01, 0x99, 0x0a, 0x00, 0x09, 0x42, 0x00, 0xff, 0xf0, + 0x7f, 0x63, 0xdb, 0x78, 0x4b, 0xff, 0xfb, 0xb1, 0x7f, 0x63, 0xdb, 0x78, + 0x38, 0x9f, 0x00, 0x08, 0x38, 0xa0, 0x00, 0x01, 0x4b, 0xff, 0xfc, 0x35, + 0x81, 0x21, 0x00, 0x00, 0x91, 0x3e, 0x00, 0x00, 0x7f, 0xc1, 0xf3, 0x78, + 0x39, 0x7f, 0x00, 0x30, 0x80, 0x0b, 0x00, 0x04, 0x3d, 0x20, 0x10, 0x00, + 0x83, 0xeb, 0xff, 0xfc, 0x7c, 0x08, 0x03, 0xa6, 0x61, 0x29, 0x00, 0xe4, + 0x81, 0x29, 0x00, 0x00, 0x39, 0x40, 0x00, 0x00, 0x83, 0x4b, 0xff, 0xe8, + 0x91, 0x49, 0x02, 0x84, 0x83, 0x6b, 0xff, 0xec, 0x83, 0x8b, 0xff, 0xf0, + 0x83, 0xab, 0xff, 0xf4, 0x83, 0xcb, 0xff, 0xf8, 0x7d, 0x61, 0x5b, 0x78, + 0x4e, 0x80, 0x00, 0x20, 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xd8, + 0x93, 0xe1, 0x00, 0x24, 0x3f, 0xe0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x2c, + 0x63, 0xff, 0x00, 0xe4, 0x93, 0x81, 0x00, 0x18, 0x7c, 0x9c, 0x23, 0x78, + 0x81, 0x3f, 0x00, 0x00, 0x93, 0xa1, 0x00, 0x1c, 0x7c, 0xbd, 0x2b, 0x78, + 0x81, 0x49, 0x02, 0x84, 0x93, 0xc1, 0x00, 0x20, 0x7c, 0x7e, 0x1b, 0x78, + 0x2f, 0x8a, 0x00, 0x00, 0x41, 0x9e, 0x00, 0x18, 0x4b, 0xf7, 0x34, 0x71, + 0x81, 0x3f, 0x00, 0x00, 0x81, 0x49, 0x02, 0x84, 0x2f, 0x8a, 0x00, 0x00, + 0x40, 0x9e, 0xff, 0xf0, 0x2f, 0x9e, 0xff, 0xff, 0x39, 0x40, 0x00, 0x01, + 0x91, 0x49, 0x02, 0x84, 0x41, 0x9e, 0x00, 0x9c, 0x39, 0x20, 0x00, 0x02, + 0x7f, 0xc3, 0xf3, 0x78, 0x38, 0x81, 0x00, 0x08, 0x38, 0xa0, 0x00, 0x05, + 0x99, 0x21, 0x00, 0x08, 0x93, 0xa1, 0x00, 0x09, 0x4b, 0xff, 0xfa, 0xd5, + 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x78, 0x7f, 0xc3, 0xf3, 0x78, + 0x38, 0x81, 0x00, 0x10, 0x38, 0xa0, 0x00, 0x01, 0x4b, 0xff, 0xfb, 0x51, + 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x60, 0x89, 0x21, 0x00, 0x10, + 0x2b, 0x89, 0x00, 0xff, 0x41, 0x9e, 0x00, 0x54, 0x7f, 0xc3, 0xf3, 0x78, + 0x7f, 0x84, 0xe3, 0x78, 0x38, 0xa0, 0x00, 0x04, 0x4b, 0xff, 0xfb, 0x2d, + 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x3c, 0x80, 0x01, 0x00, 0x2c, + 0x3d, 0x20, 0x10, 0x00, 0x61, 0x29, 0x00, 0xe4, 0x39, 0x40, 0x00, 0x00, + 0x7c, 0x08, 0x03, 0xa6, 0x81, 0x29, 0x00, 0x00, 0x83, 0x81, 0x00, 0x18, + 0x38, 0x60, 0x00, 0x00, 0x83, 0xa1, 0x00, 0x1c, 0x83, 0xc1, 0x00, 0x20, + 0x83, 0xe1, 0x00, 0x24, 0x91, 0x49, 0x02, 0x84, 0x38, 0x21, 0x00, 0x28, + 0x4e, 0x80, 0x00, 0x20, 0x80, 0x01, 0x00, 0x2c, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x39, 0x40, 0x00, 0x00, 0x7c, 0x08, 0x03, 0xa6, + 0x81, 0x29, 0x00, 0x00, 0x83, 0x81, 0x00, 0x18, 0x38, 0x60, 0xff, 0xff, + 0x83, 0xa1, 0x00, 0x1c, 0x83, 0xc1, 0x00, 0x20, 0x83, 0xe1, 0x00, 0x24, + 0x91, 0x49, 0x02, 0x84, 0x38, 0x21, 0x00, 0x28, 0x4e, 0x80, 0x00, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xd8, 0x93, 0xe1, 0x00, 0x24, + 0x3f, 0xe0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x2c, 0x63, 0xff, 0x00, 0xe4, + 0x93, 0x81, 0x00, 0x18, 0x7c, 0x7c, 0x1b, 0x78, 0x81, 0x3f, 0x00, 0x00, + 0x93, 0xa1, 0x00, 0x1c, 0x7c, 0x9d, 0x23, 0x78, 0x81, 0x49, 0x02, 0x84, + 0x93, 0xc1, 0x00, 0x20, 0x7c, 0xbe, 0x2b, 0x78, 0x2f, 0x8a, 0x00, 0x00, + 0x41, 0x9e, 0x00, 0x18, 0x4b, 0xf7, 0x33, 0x3d, 0x81, 0x3f, 0x00, 0x00, + 0x81, 0x49, 0x02, 0x84, 0x2f, 0x8a, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, + 0x39, 0x40, 0x00, 0x01, 0x7f, 0x83, 0xe3, 0x78, 0x91, 0x49, 0x02, 0x84, + 0x38, 0x81, 0x00, 0x08, 0x39, 0x20, 0x00, 0x0c, 0x38, 0xa0, 0x00, 0x09, + 0x99, 0x21, 0x00, 0x08, 0x93, 0xa1, 0x00, 0x09, 0x93, 0xc1, 0x00, 0x0d, + 0x4b, 0xff, 0xf9, 0xa5, 0x80, 0x01, 0x00, 0x2c, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x39, 0x40, 0x00, 0x00, 0x7c, 0x08, 0x03, 0xa6, + 0x81, 0x29, 0x00, 0x00, 0x83, 0x81, 0x00, 0x18, 0x83, 0xa1, 0x00, 0x1c, + 0x83, 0xc1, 0x00, 0x20, 0x83, 0xe1, 0x00, 0x24, 0x91, 0x49, 0x02, 0x84, + 0x38, 0x21, 0x00, 0x28, 0x4e, 0x80, 0x00, 0x20, 0x2f, 0x83, 0xff, 0xff, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xe0, 0x93, 0x81, 0x00, 0x10, + 0x7c, 0x7c, 0x1b, 0x78, 0x93, 0xe1, 0x00, 0x1c, 0x7c, 0x3f, 0x0b, 0x78, + 0x90, 0x01, 0x00, 0x24, 0x93, 0x61, 0x00, 0x0c, 0x93, 0xa1, 0x00, 0x14, + 0x93, 0xc1, 0x00, 0x18, 0x41, 0x9e, 0x00, 0xdc, 0x3f, 0xa0, 0x10, 0x00, + 0x7c, 0x9e, 0x23, 0x78, 0x63, 0xbd, 0x00, 0xe4, 0x7c, 0xbb, 0x2b, 0x78, + 0x81, 0x3d, 0x00, 0x00, 0x81, 0x49, 0x02, 0x84, 0x2f, 0x8a, 0x00, 0x00, + 0x41, 0x9e, 0x00, 0x18, 0x4b, 0xf7, 0x32, 0x7d, 0x81, 0x3d, 0x00, 0x00, + 0x81, 0x49, 0x02, 0x84, 0x2f, 0x8a, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, + 0x39, 0x40, 0x00, 0x01, 0x39, 0x1e, 0xff, 0xff, 0x91, 0x49, 0x02, 0x84, + 0x39, 0x20, 0x00, 0x00, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x49, 0x53, 0x78, + 0x8c, 0xe8, 0x00, 0x01, 0x39, 0x49, 0x00, 0x01, 0x2f, 0x87, 0x00, 0x00, + 0x40, 0x9e, 0xff, 0xf0, 0x39, 0x09, 0x00, 0x15, 0x80, 0xe1, 0x00, 0x00, + 0x55, 0x08, 0x00, 0x36, 0x7d, 0x46, 0x53, 0x79, 0x7d, 0x08, 0x00, 0xd0, + 0x7c, 0x3d, 0x0b, 0x78, 0x7c, 0xe1, 0x41, 0x6e, 0x38, 0xa9, 0x00, 0x06, + 0x7c, 0xc9, 0x03, 0xa6, 0x39, 0x20, 0x00, 0x00, 0x38, 0x81, 0x00, 0x08, + 0x9b, 0x61, 0x00, 0x08, 0x91, 0x44, 0x00, 0x01, 0x40, 0x81, 0x00, 0x70, + 0x7d, 0x1e, 0x48, 0xae, 0x7d, 0x44, 0x4a, 0x14, 0x39, 0x29, 0x00, 0x01, + 0x99, 0x0a, 0x00, 0x05, 0x42, 0x00, 0xff, 0xf0, 0x39, 0x20, 0x00, 0x00, + 0x7f, 0x83, 0xe3, 0x78, 0x99, 0x2a, 0x00, 0x06, 0x4b, 0xff, 0xf8, 0x89, + 0x3d, 0x40, 0x10, 0x00, 0x61, 0x4a, 0x00, 0xe4, 0x81, 0x21, 0x00, 0x00, + 0x81, 0x4a, 0x00, 0x00, 0x91, 0x3d, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, + 0x91, 0x2a, 0x02, 0x84, 0x7f, 0xa1, 0xeb, 0x78, 0x39, 0x7f, 0x00, 0x20, + 0x80, 0x0b, 0x00, 0x04, 0x83, 0xeb, 0xff, 0xfc, 0x7c, 0x08, 0x03, 0xa6, + 0x83, 0x6b, 0xff, 0xec, 0x83, 0x8b, 0xff, 0xf0, 0x83, 0xab, 0xff, 0xf4, + 0x83, 0xcb, 0xff, 0xf8, 0x7d, 0x61, 0x5b, 0x78, 0x4e, 0x80, 0x00, 0x20, + 0x39, 0x40, 0x00, 0x01, 0x7d, 0x49, 0x03, 0xa6, 0x4b, 0xff, 0xff, 0x8c, + 0x3d, 0x20, 0x01, 0x1e, 0x81, 0x29, 0xf2, 0x8c, 0x7d, 0x29, 0x03, 0xa6, + 0x4e, 0x80, 0x04, 0x20, 0x3d, 0x20, 0x01, 0x1e, 0x81, 0x29, 0xf2, 0x90, + 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, 0x3d, 0x20, 0x01, 0x1e, + 0x81, 0x29, 0xf2, 0x94, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xf0, 0x3d, 0x40, 0x0a, 0x00, + 0x93, 0xe1, 0x00, 0x0c, 0x3f, 0xe0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x14, + 0x63, 0xff, 0x00, 0xe4, 0x81, 0x3f, 0x00, 0x00, 0x7f, 0x89, 0x50, 0x00, + 0x41, 0x9e, 0x00, 0x24, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0x98, 0x83, 0xe1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x3d, 0x20, 0x10, 0x05, 0x38, 0x80, 0x00, 0x40, 0x81, 0x29, 0xe9, 0xc0, + 0x38, 0x60, 0x02, 0x88, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x21, + 0x38, 0x80, 0x00, 0x00, 0x90, 0x7f, 0x00, 0x00, 0x38, 0xa0, 0x02, 0x88, + 0x4b, 0xe5, 0x71, 0xe5, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0x98, 0x83, 0xe1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xf0, 0x3d, 0x40, 0x0a, 0x00, + 0x93, 0xe1, 0x00, 0x0c, 0x3f, 0xe0, 0x10, 0x00, 0x90, 0x01, 0x00, 0x14, + 0x63, 0xff, 0x00, 0xe4, 0x81, 0x3f, 0x00, 0x00, 0x7f, 0x89, 0x50, 0x00, + 0x41, 0x9e, 0x00, 0x24, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0x9c, 0x83, 0xe1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x3d, 0x20, 0x10, 0x05, 0x38, 0x80, 0x00, 0x40, 0x81, 0x29, 0xe9, 0xc0, + 0x38, 0x60, 0x02, 0x88, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x21, + 0x38, 0x80, 0x00, 0x00, 0x90, 0x7f, 0x00, 0x00, 0x38, 0xa0, 0x02, 0x88, + 0x4b, 0xe5, 0x71, 0x55, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0x9c, 0x83, 0xe1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x3d, 0x20, 0x01, 0x1e, 0x94, 0x21, 0xff, 0xf0, + 0x81, 0x29, 0xf2, 0xa0, 0x93, 0xe1, 0x00, 0x0c, 0x7d, 0x29, 0x03, 0xa6, + 0x90, 0x01, 0x00, 0x14, 0x4e, 0x80, 0x04, 0x21, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x3d, 0x40, 0x0a, 0x00, 0x81, 0x29, 0x00, 0x00, + 0x7c, 0x7f, 0x1b, 0x78, 0x7f, 0x89, 0x50, 0x00, 0x41, 0x9e, 0x00, 0x18, + 0x2b, 0x83, 0x00, 0x1f, 0x41, 0x9d, 0x00, 0x10, 0x54, 0x63, 0x10, 0x3a, + 0x7c, 0x69, 0x1a, 0x14, 0x4b, 0xff, 0xf7, 0xbd, 0x80, 0x01, 0x00, 0x14, + 0x7f, 0xe3, 0xfb, 0x78, 0x83, 0xe1, 0x00, 0x0c, 0x7c, 0x08, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x4e, 0x80, 0x00, 0x20, 0x7c, 0x08, 0x02, 0xa6, + 0x3d, 0x20, 0x01, 0x1e, 0x94, 0x21, 0xff, 0xf0, 0x81, 0x29, 0xf2, 0xa4, + 0x93, 0xc1, 0x00, 0x08, 0x7c, 0x7e, 0x1b, 0x78, 0x93, 0xe1, 0x00, 0x0c, + 0x7d, 0x29, 0x03, 0xa6, 0x90, 0x01, 0x00, 0x14, 0x4e, 0x80, 0x04, 0x21, + 0x3d, 0x20, 0x10, 0x00, 0x61, 0x29, 0x00, 0xe4, 0x7c, 0x7f, 0x1b, 0x78, + 0x80, 0xe9, 0x00, 0x00, 0x3d, 0x20, 0x0a, 0x00, 0x7f, 0x87, 0x48, 0x00, + 0x41, 0x9e, 0x00, 0x5c, 0x2f, 0x83, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x54, + 0x39, 0x00, 0x00, 0x20, 0x39, 0x47, 0x00, 0x7c, 0x39, 0x20, 0x00, 0x00, + 0x7d, 0x09, 0x03, 0xa6, 0x48, 0x00, 0x00, 0x0c, 0x39, 0x29, 0x00, 0x01, + 0x42, 0x40, 0x00, 0x38, 0x85, 0x0a, 0x00, 0x04, 0x2f, 0x88, 0x00, 0x00, + 0x40, 0x9e, 0xff, 0xf0, 0x39, 0x49, 0x00, 0x20, 0x39, 0x29, 0x00, 0x40, + 0x55, 0x4a, 0x10, 0x3a, 0x55, 0x29, 0x10, 0x3a, 0x7f, 0xc7, 0x51, 0x2e, + 0x3d, 0x40, 0x10, 0x00, 0x61, 0x4a, 0x00, 0xe4, 0x80, 0x6a, 0x00, 0x00, + 0x7c, 0x63, 0x4a, 0x14, 0x4b, 0xff, 0xf7, 0x09, 0x80, 0x01, 0x00, 0x14, + 0x7f, 0xe3, 0xfb, 0x78, 0x83, 0xc1, 0x00, 0x08, 0x7c, 0x08, 0x03, 0xa6, + 0x83, 0xe1, 0x00, 0x0c, 0x38, 0x21, 0x00, 0x10, 0x4e, 0x80, 0x00, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xf0, 0x3d, 0x20, 0x10, 0x00, + 0x3d, 0x40, 0x0a, 0x00, 0x61, 0x29, 0x00, 0xe4, 0x93, 0xe1, 0x00, 0x0c, + 0x90, 0x01, 0x00, 0x14, 0x7c, 0x7f, 0x1b, 0x78, 0x81, 0x29, 0x00, 0x00, + 0x7f, 0x89, 0x50, 0x00, 0x41, 0x9e, 0x00, 0x18, 0x2b, 0x83, 0x00, 0x1f, + 0x41, 0x9d, 0x00, 0x10, 0x54, 0x6a, 0x10, 0x3a, 0x7c, 0x69, 0x50, 0x2e, + 0x4b, 0xff, 0xf7, 0xa9, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0xa8, 0x7f, 0xe3, 0xfb, 0x78, 0x7c, 0x08, 0x03, 0xa6, + 0x83, 0xe1, 0x00, 0x0c, 0x38, 0x21, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, + 0x4e, 0x80, 0x04, 0x20, 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xf0, + 0x3d, 0x20, 0x10, 0x00, 0x61, 0x29, 0x00, 0xe4, 0x93, 0xc1, 0x00, 0x08, + 0x90, 0x01, 0x00, 0x14, 0x7c, 0x7e, 0x1b, 0x78, 0x93, 0xe1, 0x00, 0x0c, + 0x81, 0x09, 0x00, 0x00, 0x3d, 0x20, 0x0a, 0x00, 0x7f, 0x88, 0x48, 0x00, + 0x41, 0x9e, 0x00, 0x58, 0x39, 0x40, 0x00, 0x20, 0x39, 0x28, 0x00, 0x7c, + 0x3b, 0xe0, 0x00, 0x00, 0x7d, 0x49, 0x03, 0xa6, 0x48, 0x00, 0x00, 0x0c, + 0x3b, 0xff, 0x00, 0x01, 0x42, 0x40, 0x00, 0x3c, 0x85, 0x49, 0x00, 0x04, + 0x7f, 0x9e, 0x50, 0x00, 0x40, 0x9e, 0xff, 0xf0, 0x39, 0x3f, 0x00, 0x40, + 0x3b, 0xff, 0x00, 0x20, 0x55, 0x29, 0x10, 0x3a, 0x57, 0xff, 0x10, 0x3a, + 0x7c, 0x68, 0x48, 0x2e, 0x4b, 0xff, 0xf7, 0x15, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x39, 0x40, 0x00, 0x00, 0x81, 0x29, 0x00, 0x00, + 0x7d, 0x49, 0xf9, 0x2e, 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x14, + 0x81, 0x29, 0xf2, 0xac, 0x7f, 0xc3, 0xf3, 0x78, 0x83, 0xe1, 0x00, 0x0c, + 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xc1, 0x00, 0x08, 0x7d, 0x29, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x10, 0x4e, 0x80, 0x04, 0x20, 0x94, 0x21, 0xfd, 0x48, + 0x7c, 0x08, 0x02, 0xa6, 0x39, 0x28, 0x00, 0x01, 0x92, 0xa1, 0x02, 0x8c, + 0x7c, 0xd5, 0x33, 0x78, 0x93, 0x01, 0x02, 0x98, 0x7c, 0x98, 0x23, 0x78, + 0x93, 0x61, 0x02, 0xa4, 0x7c, 0xa4, 0x2b, 0x78, 0x93, 0xe1, 0x02, 0xb4, + 0x7c, 0xfb, 0x3b, 0x78, 0x7c, 0xbf, 0x2b, 0x78, 0x38, 0xe0, 0xff, 0xff, + 0x7c, 0xc5, 0x33, 0x78, 0x38, 0xc1, 0x02, 0x7c, 0x93, 0xc1, 0x02, 0xb0, + 0x7c, 0x7e, 0x1b, 0x78, 0x90, 0x01, 0x02, 0xbc, 0x92, 0x81, 0x02, 0x88, + 0x92, 0xc1, 0x02, 0x90, 0x92, 0xe1, 0x02, 0x94, 0x93, 0x21, 0x02, 0x9c, + 0x93, 0x41, 0x02, 0xa0, 0x93, 0x81, 0x02, 0xa8, 0x93, 0xa1, 0x02, 0xac, + 0x91, 0x01, 0x02, 0x7c, 0x91, 0x21, 0x02, 0x78, 0x4b, 0xe9, 0x0a, 0xd1, + 0x2c, 0x03, 0x00, 0x00, 0x40, 0x82, 0x02, 0xf4, 0x39, 0x40, 0x00, 0x72, + 0x3f, 0x80, 0x10, 0x00, 0x99, 0x41, 0x02, 0x80, 0x3b, 0x20, 0x00, 0x2f, + 0x98, 0x61, 0x02, 0x81, 0x3b, 0x40, 0x00, 0x00, 0x63, 0x9c, 0x00, 0xe4, + 0x57, 0x1d, 0x10, 0x3a, 0x3e, 0xc0, 0x10, 0x05, 0x3e, 0xe0, 0x10, 0x0b, + 0x80, 0xa1, 0x02, 0x7c, 0x7f, 0xc3, 0xf3, 0x78, 0x7f, 0xe4, 0xfb, 0x78, + 0x38, 0xc1, 0x00, 0x08, 0x38, 0xe0, 0xff, 0xff, 0x4b, 0xe9, 0x0b, 0x79, + 0x2f, 0x83, 0x00, 0x00, 0x40, 0x9e, 0x01, 0xf8, 0x89, 0x75, 0x00, 0x00, + 0x2f, 0x8b, 0x00, 0x00, 0x41, 0x9e, 0x02, 0x94, 0x39, 0x81, 0x01, 0x6b, + 0x39, 0x20, 0x00, 0x00, 0x39, 0x29, 0x00, 0x01, 0x9d, 0x6c, 0x00, 0x01, + 0x7d, 0x75, 0x48, 0xae, 0x2f, 0x8b, 0x00, 0x00, 0x40, 0x9e, 0xff, 0xf0, + 0x39, 0x89, 0x00, 0x01, 0x89, 0x61, 0x00, 0x6c, 0x39, 0x41, 0x00, 0x08, + 0x7d, 0x2a, 0x4a, 0x14, 0x2f, 0x8b, 0x00, 0x00, 0x9b, 0x29, 0x01, 0x64, + 0x41, 0x9e, 0x00, 0x28, 0x39, 0x21, 0x01, 0x6c, 0x38, 0xcc, 0xff, 0xff, + 0x7c, 0xc9, 0x32, 0x14, 0x39, 0x21, 0x00, 0x6c, 0x9d, 0x66, 0x00, 0x01, + 0x39, 0x8c, 0x00, 0x01, 0x8d, 0x69, 0x00, 0x01, 0x2f, 0x8b, 0x00, 0x00, + 0x40, 0x9e, 0xff, 0xf0, 0x39, 0x41, 0x00, 0x08, 0x38, 0x81, 0x01, 0x6c, + 0x7d, 0x8a, 0x62, 0x14, 0x38, 0xa0, 0x00, 0xfb, 0x9b, 0x4c, 0x01, 0x64, + 0x81, 0x3c, 0x00, 0x00, 0x7c, 0x69, 0xe8, 0x2e, 0x4b, 0xff, 0xfa, 0x01, + 0x81, 0x21, 0x00, 0x08, 0x2f, 0x89, 0x00, 0x00, 0x41, 0x9c, 0x01, 0xbc, + 0x39, 0x20, 0x00, 0x66, 0x9b, 0x41, 0x02, 0x70, 0x99, 0x21, 0x02, 0x6c, + 0x39, 0x20, 0x00, 0x69, 0x99, 0x21, 0x02, 0x6d, 0x39, 0x20, 0x00, 0x6c, + 0x99, 0x21, 0x02, 0x6e, 0x39, 0x20, 0x00, 0x65, 0x99, 0x21, 0x02, 0x6f, + 0x38, 0x81, 0x02, 0x6c, 0x38, 0xa0, 0x00, 0xfb, 0x81, 0x3c, 0x00, 0x00, + 0x7c, 0x69, 0xe8, 0x2e, 0x4b, 0xff, 0xf9, 0xbd, 0x7f, 0xc3, 0xf3, 0x78, + 0x7f, 0xe4, 0xfb, 0x78, 0x38, 0xa1, 0x01, 0x6c, 0x38, 0xc1, 0x02, 0x80, + 0x38, 0xe1, 0x02, 0x78, 0x7f, 0x68, 0xdb, 0x78, 0x4b, 0xe9, 0x02, 0x85, + 0x2f, 0x83, 0x00, 0x00, 0x41, 0xbc, 0xfe, 0xf4, 0x81, 0x3c, 0x00, 0x00, + 0x38, 0x81, 0x01, 0x6c, 0x38, 0xa0, 0x00, 0xfb, 0x7c, 0x69, 0xe8, 0x2e, + 0x4b, 0xff, 0xf9, 0x85, 0x81, 0x3c, 0x00, 0x00, 0x80, 0xc1, 0x02, 0x78, + 0x7f, 0x04, 0xc3, 0x78, 0x7c, 0x69, 0xe8, 0x2e, 0x38, 0xa1, 0x01, 0x6c, + 0x4b, 0xff, 0xf5, 0x09, 0x81, 0x36, 0xe9, 0xc0, 0x38, 0x60, 0x00, 0x00, + 0x38, 0x80, 0x00, 0x40, 0x60, 0x63, 0xc8, 0x00, 0x7d, 0x29, 0x03, 0xa6, + 0x4e, 0x80, 0x04, 0x21, 0x7c, 0x74, 0x1b, 0x78, 0x48, 0x00, 0x00, 0x10, + 0x80, 0xc1, 0x02, 0x78, 0x7c, 0x69, 0xe8, 0x2e, 0x4b, 0xff, 0xf6, 0x31, + 0x81, 0x01, 0x02, 0x78, 0x38, 0xe0, 0x00, 0x00, 0x7f, 0xe4, 0xfb, 0x78, + 0x7e, 0x85, 0xa3, 0x78, 0x39, 0x20, 0x00, 0x00, 0x38, 0xc0, 0x00, 0x01, + 0x60, 0xe7, 0xc8, 0x00, 0x7f, 0x6a, 0xdb, 0x78, 0x7f, 0xc3, 0xf3, 0x78, + 0x4b, 0xe9, 0x03, 0x89, 0x7e, 0x84, 0xa3, 0x78, 0x2f, 0x83, 0x00, 0x00, + 0x7c, 0x65, 0x1b, 0x78, 0x90, 0x61, 0x02, 0x74, 0x81, 0x3c, 0x00, 0x00, + 0x41, 0x9d, 0xff, 0xb8, 0x7c, 0x69, 0xe8, 0x2e, 0x38, 0x81, 0x02, 0x74, + 0x80, 0xa1, 0x02, 0x78, 0x4b, 0xff, 0xf7, 0x0d, 0x80, 0xa1, 0x02, 0x78, + 0x7f, 0x67, 0xdb, 0x78, 0x7f, 0xe4, 0xfb, 0x78, 0x38, 0xc0, 0x00, 0x00, + 0x7f, 0xc3, 0xf3, 0x78, 0x4b, 0xe9, 0x07, 0x71, 0x81, 0x37, 0x48, 0x7c, + 0x7e, 0x83, 0xa3, 0x78, 0x7d, 0x29, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x21, + 0x80, 0xa1, 0x02, 0x78, 0x7f, 0xe4, 0xfb, 0x78, 0x38, 0xc0, 0xff, 0xff, + 0x7f, 0xc3, 0xf3, 0x78, 0x4b, 0xe9, 0x02, 0xa5, 0x80, 0xa1, 0x02, 0x7c, + 0x7f, 0xc3, 0xf3, 0x78, 0x7f, 0xe4, 0xfb, 0x78, 0x38, 0xc1, 0x00, 0x08, + 0x38, 0xe0, 0xff, 0xff, 0x4b, 0xe9, 0x09, 0x85, 0x2f, 0x83, 0x00, 0x00, + 0x41, 0x9e, 0xfe, 0x10, 0x80, 0xa1, 0x02, 0x7c, 0x7f, 0xc3, 0xf3, 0x78, + 0x7f, 0xe4, 0xfb, 0x78, 0x38, 0xc0, 0x00, 0x00, 0x4b, 0xe9, 0x08, 0xe9, + 0x38, 0x60, 0x00, 0x00, 0x80, 0x01, 0x02, 0xbc, 0x82, 0x81, 0x02, 0x88, + 0x7c, 0x08, 0x03, 0xa6, 0x82, 0xa1, 0x02, 0x8c, 0x82, 0xc1, 0x02, 0x90, + 0x82, 0xe1, 0x02, 0x94, 0x83, 0x01, 0x02, 0x98, 0x83, 0x21, 0x02, 0x9c, + 0x83, 0x41, 0x02, 0xa0, 0x83, 0x61, 0x02, 0xa4, 0x83, 0x81, 0x02, 0xa8, + 0x83, 0xa1, 0x02, 0xac, 0x83, 0xc1, 0x02, 0xb0, 0x83, 0xe1, 0x02, 0xb4, + 0x38, 0x21, 0x02, 0xb8, 0x4e, 0x80, 0x00, 0x20, 0x39, 0x20, 0x00, 0x64, + 0x9b, 0x41, 0x02, 0x6f, 0x99, 0x21, 0x02, 0x6c, 0x39, 0x20, 0x00, 0x69, + 0x99, 0x21, 0x02, 0x6d, 0x39, 0x20, 0x00, 0x72, 0x99, 0x21, 0x02, 0x6e, + 0x38, 0x81, 0x02, 0x6c, 0x38, 0xa0, 0x00, 0xfb, 0x81, 0x3c, 0x00, 0x00, + 0x7c, 0x69, 0xe8, 0x2e, 0x4b, 0xff, 0xf8, 0x0d, 0x81, 0x01, 0x02, 0x78, + 0x7f, 0xc3, 0xf3, 0x78, 0x7f, 0x04, 0xc3, 0x78, 0x7f, 0xe5, 0xfb, 0x78, + 0x38, 0xc1, 0x01, 0x6c, 0x7f, 0x67, 0xdb, 0x78, 0x4b, 0xff, 0xfc, 0xad, + 0x4b, 0xff, 0xfd, 0x48, 0x39, 0x80, 0x00, 0x01, 0x39, 0x20, 0x00, 0x00, + 0x4b, 0xff, 0xfd, 0x88, 0x38, 0x60, 0xff, 0xff, 0x4b, 0xff, 0xff, 0x60, + 0x94, 0x21, 0xfe, 0xa8, 0x7c, 0x08, 0x02, 0xa6, 0x39, 0x20, 0x00, 0x30, + 0x38, 0xe0, 0x00, 0x2f, 0x93, 0xe1, 0x01, 0x54, 0x3b, 0xe0, 0x00, 0x6c, + 0x90, 0x01, 0x01, 0x5c, 0x38, 0x00, 0x00, 0x76, 0x9b, 0xe1, 0x01, 0x0b, + 0x3b, 0xe0, 0x00, 0x73, 0x99, 0x21, 0x01, 0x15, 0x39, 0x00, 0x00, 0x6f, + 0x99, 0x21, 0x01, 0x16, 0x39, 0x40, 0x00, 0x00, 0x99, 0x21, 0x01, 0x17, + 0x39, 0x60, 0x00, 0x6d, 0x99, 0x21, 0x01, 0x18, 0x99, 0x21, 0x01, 0x19, + 0x99, 0x21, 0x01, 0x1a, 0x99, 0x21, 0x01, 0x1b, 0x39, 0x20, 0x00, 0x63, + 0x98, 0xe1, 0x01, 0x08, 0x98, 0x01, 0x01, 0x09, 0x98, 0xe1, 0x01, 0x0c, + 0x9b, 0xe1, 0x01, 0x0d, 0x3b, 0xe0, 0x00, 0x61, 0x98, 0x01, 0x01, 0x0f, + 0x38, 0x00, 0x00, 0x65, 0x98, 0xe1, 0x01, 0x11, 0x38, 0xe0, 0x00, 0x38, + 0x99, 0x21, 0x01, 0x20, 0x39, 0x20, 0x00, 0x6e, 0x93, 0x41, 0x01, 0x40, + 0x7c, 0x7a, 0x1b, 0x78, 0x93, 0x61, 0x01, 0x44, 0x7c, 0x9b, 0x23, 0x78, + 0x93, 0x81, 0x01, 0x48, 0x7c, 0xbc, 0x2b, 0x78, 0x93, 0xa1, 0x01, 0x4c, + 0x7c, 0xdd, 0x33, 0x78, 0x93, 0xc1, 0x01, 0x50, 0x3b, 0xc0, 0x00, 0x00, + 0x99, 0x01, 0x01, 0x0a, 0x99, 0x41, 0x01, 0x12, 0x98, 0xe1, 0x01, 0x14, + 0x38, 0xe1, 0x01, 0x09, 0x99, 0x41, 0x01, 0x1c, 0x99, 0x01, 0x01, 0x21, + 0x93, 0x21, 0x01, 0x3c, 0x9b, 0xe1, 0x01, 0x0e, 0x98, 0x01, 0x01, 0x10, + 0x99, 0x61, 0x01, 0x22, 0x99, 0x61, 0x01, 0x23, 0x99, 0x01, 0x01, 0x24, + 0x39, 0x01, 0x00, 0x07, 0x99, 0x21, 0x01, 0x25, 0x39, 0x20, 0x00, 0x76, + 0x99, 0x41, 0x01, 0x26, 0x39, 0x40, 0x00, 0x2f, 0x48, 0x00, 0x00, 0x08, + 0x8d, 0x27, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x9d, 0x48, 0x00, 0x01, + 0x3b, 0xde, 0x00, 0x01, 0x7d, 0x2a, 0x4b, 0x78, 0x40, 0x9e, 0xff, 0xec, + 0x39, 0x21, 0x00, 0x08, 0x3b, 0x3e, 0xff, 0xff, 0x7f, 0x29, 0xca, 0x14, + 0x38, 0xc1, 0x01, 0x15, 0x7f, 0x27, 0xcb, 0x78, 0x7f, 0xca, 0xf3, 0x78, + 0x39, 0x20, 0x00, 0x30, 0x39, 0x00, 0x00, 0x38, 0x48, 0x00, 0x00, 0x08, + 0x8d, 0x26, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x9d, 0x07, 0x00, 0x01, + 0x39, 0x4a, 0x00, 0x01, 0x7d, 0x28, 0x4b, 0x78, 0x40, 0x9e, 0xff, 0xec, + 0x7d, 0x41, 0x52, 0x14, 0x3b, 0xe0, 0x00, 0x01, 0x99, 0x2a, 0x00, 0x08, + 0x48, 0x00, 0x00, 0x28, 0x2f, 0x89, 0x00, 0x09, 0x39, 0x49, 0x00, 0x57, + 0x99, 0x01, 0x00, 0x18, 0x39, 0x29, 0x00, 0x30, 0x41, 0x9d, 0x00, 0x5c, + 0x2f, 0x9f, 0x01, 0x00, 0x99, 0x21, 0x00, 0x19, 0x3b, 0xff, 0x00, 0x01, + 0x41, 0x9e, 0x00, 0x5c, 0x39, 0x00, 0x00, 0x32, 0x7f, 0x43, 0xd3, 0x78, + 0x7f, 0xa4, 0xeb, 0x78, 0x7f, 0x65, 0xdb, 0x78, 0x38, 0xc1, 0x00, 0x08, + 0x7f, 0x87, 0xe3, 0x78, 0x4b, 0xff, 0xfb, 0x01, 0x7f, 0xe9, 0x26, 0x70, + 0x2f, 0x89, 0x00, 0x09, 0x39, 0x49, 0x00, 0x57, 0x39, 0x09, 0x00, 0x30, + 0x57, 0xe9, 0x07, 0x3e, 0x40, 0xbd, 0xff, 0xac, 0x2f, 0x89, 0x00, 0x09, + 0x99, 0x41, 0x00, 0x18, 0x39, 0x49, 0x00, 0x57, 0x39, 0x29, 0x00, 0x30, + 0x40, 0xbd, 0xff, 0xac, 0x2f, 0x9f, 0x01, 0x00, 0x99, 0x41, 0x00, 0x19, + 0x3b, 0xff, 0x00, 0x01, 0x40, 0x9e, 0xff, 0xac, 0x39, 0x01, 0x01, 0x21, + 0x7f, 0x2a, 0xcb, 0x78, 0x3b, 0xe0, 0x00, 0x6f, 0x39, 0x20, 0x00, 0x63, + 0x48, 0x00, 0x00, 0x08, 0x8f, 0xe8, 0x00, 0x01, 0x2f, 0x9f, 0x00, 0x00, + 0x9d, 0x2a, 0x00, 0x01, 0x3b, 0xde, 0x00, 0x01, 0x7f, 0xe9, 0xfb, 0x78, + 0x40, 0x9e, 0xff, 0xec, 0x7f, 0xc1, 0xf2, 0x14, 0x3f, 0x20, 0x10, 0x00, + 0x9b, 0xfe, 0x00, 0x08, 0x63, 0x39, 0x00, 0xe4, 0x57, 0xbe, 0x10, 0x3a, + 0x38, 0x81, 0x00, 0x08, 0x81, 0x39, 0x00, 0x00, 0x38, 0xa0, 0x00, 0xfb, + 0x7c, 0x69, 0xf0, 0x2e, 0x4b, 0xff, 0xf5, 0xb5, 0x7f, 0xa4, 0xeb, 0x78, + 0x7f, 0x65, 0xdb, 0x78, 0x38, 0xc1, 0x00, 0x08, 0x7f, 0x87, 0xe3, 0x78, + 0x7f, 0x43, 0xd3, 0x78, 0x39, 0x00, 0x00, 0x3c, 0x4b, 0xff, 0xfa, 0x55, + 0x39, 0x20, 0x00, 0x64, 0x99, 0x21, 0x01, 0x28, 0x39, 0x20, 0x00, 0x6f, + 0x99, 0x21, 0x01, 0x29, 0x39, 0x20, 0x00, 0x6e, 0x99, 0x21, 0x01, 0x2a, + 0x39, 0x20, 0x00, 0x65, 0x99, 0x21, 0x01, 0x2b, 0x39, 0x20, 0x00, 0x21, + 0x9b, 0xe1, 0x01, 0x2d, 0x38, 0x81, 0x01, 0x28, 0x99, 0x21, 0x01, 0x2c, + 0x38, 0xa0, 0x00, 0xfb, 0x81, 0x39, 0x00, 0x00, 0x7c, 0x69, 0xf0, 0x2e, + 0x4b, 0xff, 0xf5, 0x59, 0x80, 0x01, 0x01, 0x5c, 0x83, 0x21, 0x01, 0x3c, + 0x7c, 0x08, 0x03, 0xa6, 0x83, 0x41, 0x01, 0x40, 0x83, 0x61, 0x01, 0x44, + 0x83, 0x81, 0x01, 0x48, 0x83, 0xa1, 0x01, 0x4c, 0x83, 0xc1, 0x01, 0x50, + 0x83, 0xe1, 0x01, 0x54, 0x38, 0x21, 0x01, 0x58, 0x4e, 0x80, 0x00, 0x20, + 0x7c, 0x08, 0x02, 0xa6, 0x94, 0x21, 0xff, 0xe0, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x93, 0x81, 0x00, 0x10, 0x90, 0x01, 0x00, 0x24, + 0x7c, 0xbc, 0x2b, 0x78, 0x93, 0xa1, 0x00, 0x14, 0x7c, 0xdd, 0x33, 0x78, + 0x81, 0x69, 0x00, 0x00, 0x3d, 0x20, 0x0a, 0x00, 0x93, 0xc1, 0x00, 0x18, + 0x7c, 0x9e, 0x23, 0x78, 0x7f, 0x8b, 0x48, 0x00, 0x93, 0xe1, 0x00, 0x1c, + 0x7c, 0x7f, 0x1b, 0x78, 0x41, 0x9e, 0x00, 0x38, 0x39, 0x40, 0x00, 0x20, + 0x39, 0x2b, 0x00, 0x7c, 0x38, 0xc0, 0x00, 0x00, 0x7d, 0x49, 0x03, 0xa6, + 0x48, 0x00, 0x00, 0x0c, 0x38, 0xc6, 0x00, 0x01, 0x42, 0x40, 0x00, 0x1c, + 0x85, 0x09, 0x00, 0x04, 0x7f, 0x9f, 0x40, 0x00, 0x40, 0x9e, 0xff, 0xf0, + 0x81, 0x2b, 0x02, 0x80, 0x2f, 0x89, 0x00, 0x00, 0x41, 0x9e, 0x00, 0x40, + 0x3d, 0x20, 0x01, 0x1e, 0x80, 0x01, 0x00, 0x24, 0x81, 0x29, 0xf2, 0xb0, + 0x7f, 0xe3, 0xfb, 0x78, 0x7f, 0xc4, 0xf3, 0x78, 0x83, 0xe1, 0x00, 0x1c, + 0x83, 0xc1, 0x00, 0x18, 0x7f, 0x85, 0xe3, 0x78, 0x7f, 0xa6, 0xeb, 0x78, + 0x83, 0x81, 0x00, 0x10, 0x83, 0xa1, 0x00, 0x14, 0x7d, 0x29, 0x03, 0xa6, + 0x38, 0x21, 0x00, 0x20, 0x7c, 0x08, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x7f, 0xe3, 0xfb, 0x78, 0x7f, 0xc4, 0xf3, 0x78, 0x7c, 0xe5, 0x3b, 0x78, + 0x90, 0xe1, 0x00, 0x08, 0x4b, 0xff, 0xfc, 0x91, 0x3d, 0x20, 0x10, 0x00, + 0x61, 0x29, 0x00, 0xe4, 0x39, 0x40, 0x00, 0x02, 0x81, 0x29, 0x00, 0x00, + 0x7f, 0xe3, 0xfb, 0x78, 0x80, 0x01, 0x00, 0x24, 0x7f, 0xc4, 0xf3, 0x78, + 0x91, 0x49, 0x02, 0x80, 0x3d, 0x20, 0x01, 0x1e, 0x81, 0x29, 0xf2, 0xb0, + 0x7f, 0x85, 0xe3, 0x78, 0x80, 0xe1, 0x00, 0x08, 0x7f, 0xa6, 0xeb, 0x78, + 0x83, 0x81, 0x00, 0x10, 0x7d, 0x29, 0x03, 0xa6, 0x83, 0xa1, 0x00, 0x14, + 0x83, 0xc1, 0x00, 0x18, 0x7c, 0x08, 0x03, 0xa6, 0x83, 0xe1, 0x00, 0x1c, + 0x38, 0x21, 0x00, 0x20, 0x4e, 0x80, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned int cafiine_text_bin_len = 4788; diff --git a/server/saviine_server.exe b/server/saviine_server.exe new file mode 100644 index 0000000..dab8131 Binary files /dev/null and b/server/saviine_server.exe differ diff --git a/server/src/.vs/cafiine_server/v14/.suo b/server/src/.vs/cafiine_server/v14/.suo new file mode 100644 index 0000000..ed48b9a Binary files /dev/null and b/server/src/.vs/cafiine_server/v14/.suo differ diff --git a/server/src/Program.cs b/server/src/Program.cs new file mode 100644 index 0000000..ae0477b --- /dev/null +++ b/server/src/Program.cs @@ -0,0 +1,335 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Collections.Generic; + +namespace saviine_server +{ + class Program + { + public const byte BYTE_NORMAL = 0xff; + public const byte BYTE_SPECIAL = 0xfe; + //public const byte BYTE_OPEN = 0x00; + // public const byte BYTE_READ = 0x01; + public const byte BYTE_CLOSE = 0x02; + //public const byte BYTE_OK = 0x03; + //public const byte BYTE_SETPOS = 0x04; + //public const byte BYTE_STATFILE = 0x05; + //public const byte BYTE_EOF = 0x06; + //public const byte BYTE_GETPOS = 0x07; + //public const byte BYTE_REQUEST = 0x08; + //public const byte BYTE_REQUEST_SLOW = 0x09; + public const byte BYTE_HANDLE = 0x0A; + public const byte BYTE_DUMP = 0x0B; + public const byte BYTE_PING = 0x0C; + + public const byte BYTE_LOG_STR = 0xFB; + + [Flags] + public enum FSStatFlag : uint + { + None = 0, + unk_14_present = 0x01000000, + mtime_present = 0x04000000, + ctime_present = 0x08000000, + entid_present = 0x10000000, + directory = 0x80000000, + } + + [StructLayout(LayoutKind.Sequential)] + public struct FSStat + { + public FSStatFlag flags; + public uint permission; + public uint owner; + public uint group; + public uint file_size; + public uint unk_14_nonzero; + public uint unk_18_zero; + public uint unk_1c_zero; + public uint ent_id; + public uint ctime_u; + public uint ctime_l; + public uint mtime_u; + public uint mtime_l; + public uint unk_34_zero; + public uint unk_38_zero; + public uint unk_3c_zero; + public uint unk_40_zero; + public uint unk_44_zero; + public uint unk_48_zero; + public uint unk_4c_zero; + public uint unk_50_zero; + public uint unk_54_zero; + public uint unk_58_zero; + public uint unk_5c_zero; + public uint unk_60_zero; + } + + public static string root = "saviine_root"; + public static string logs_root = "logs"; + + const uint BUFFER_SIZE = 64 * 1024; + + static void Main(string[] args) + { + if (args.Length > 1) + { + Console.Error.WriteLine("Usage: saviine_server [rootdir]"); + return; + } + if (args.Length == 1) + { + root = args[0]; + } + // Check for cafiine_root and logs folder + if (!Directory.Exists(root)) + { + Console.Error.WriteLine("Root directory `{0}' does not exist!", root); + Directory.CreateDirectory(root); + Console.WriteLine("Root directory `{0}' created!", root); + } + if (!Directory.Exists(logs_root)) + { + Console.Error.WriteLine("Logs directory `{0}' does not exist!", logs_root); + Directory.CreateDirectory(logs_root); + Console.WriteLine("Logs directory `{0}' created!", logs_root); + } + // Delete logs + System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(logs_root); + foreach (FileInfo file in downloadedMessageInfo.GetFiles()) + { + file.Delete(); + } + + // Start server + string name = "[listener]"; + try + { + TcpListener listener = new TcpListener(IPAddress.Any, 7332); + listener.Start(); + Console.WriteLine(name + " Listening on 7332"); + + int index = 0; + while (true) + { + TcpClient client = listener.AcceptTcpClient(); + Console.WriteLine("connected"); + Thread thread = new Thread(Handle); + thread.Name = "[" + index.ToString() + "]"; + thread.Start(client); + index++; + } + } + catch (Exception e) + { + Console.WriteLine(name + " " + e.Message); + } + Console.WriteLine(name + " Exit"); + } + + static void Log(StreamWriter log, String str) + { + log.WriteLine(str); + log.Flush(); + Console.WriteLine(str); + } + + static void Handle(object client_obj) + { + string name = Thread.CurrentThread.Name; + FileStream[] files = new FileStream[256]; + Dictionary files_request = new Dictionary(); + StreamWriter log = null; + + try + { + TcpClient client = (TcpClient)client_obj; + using (NetworkStream stream = client.GetStream()) + { + EndianBinaryReader reader = new EndianBinaryReader(stream); + EndianBinaryWriter writer = new EndianBinaryWriter(stream); + + uint[] ids = reader.ReadUInt32s(4); + + // Log connection + Console.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString()); + Console.WriteLine(name + " TitleID: " + ids[0].ToString("X8") + "-" + ids[1].ToString("X8")); + + + string LocalRoot = root + "\\" + ids[0].ToString("X8") + "-" + ids[1].ToString("X8") + "\\"; + if (!ids[0].ToString("X8").Equals("00050000")) + { + writer.Write(BYTE_NORMAL); + throw new Exception("Not interested."); + } + else + { + if (!Directory.Exists(LocalRoot)) + { + Directory.CreateDirectory(LocalRoot); + } + } + + // Create log file for current thread + log = new StreamWriter(logs_root + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "-" + name + "-" + ids[0].ToString("X8") + "-" + ids[1].ToString("X8") + ".txt", true, Encoding.ASCII, 1024*64); + log.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString()); + log.WriteLine(name + " TitleID: " + ids[0].ToString("X8") + "-" + ids[1].ToString("X8")); + + writer.Write(BYTE_SPECIAL); + + while (true) + { + byte cmd_byte = reader.ReadByte(); + switch (cmd_byte) + { + case BYTE_HANDLE: + { + // Read buffer params : fd, path length, path string + int fd = reader.ReadInt32(); + int len_path = reader.ReadInt32(); + string path = reader.ReadString(Encoding.ASCII, len_path - 1); + if (reader.ReadByte() != 0) throw new InvalidDataException(); + if (!Directory.Exists(LocalRoot + path)) + { + Directory.CreateDirectory(Path.GetDirectoryName(LocalRoot + path)); + } + + // Add new file for incoming data + files_request.Add(fd, new FileStream(LocalRoot + path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write)); + + // Send response + writer.Write(BYTE_SPECIAL); + break; + } + case BYTE_DUMP: + { + // Read buffer params : fd, size, file data + int fd = reader.ReadInt32(); + int sz = reader.ReadInt32(); + byte[] buffer = new byte[sz]; + buffer = reader.ReadBytes(sz); + + // Look for file descriptor + foreach (var item in files_request) + { + if (item.Key == fd) + { + FileStream dump_file = item.Value; + if (dump_file == null) + break; + + Log(log, name + " -> dump(\"" + Path.GetFileName(dump_file.Name) + "\") " + (sz / 1024).ToString() + "kB"); + + // Write to file + dump_file.Write(buffer, 0, sz); + + break; + } + } + + // Send response + writer.Write(BYTE_SPECIAL); + break; + } + case BYTE_CLOSE: + { + int fd = reader.ReadInt32(); + if ((fd & 0x0fff00ff) == 0x0fff00ff) + { + int handle = (fd >> 8) & 0xff; + if (files[handle] == null) + { + writer.Write(BYTE_SPECIAL); + writer.Write(-38); + break; + } + Log(log, name + " close(" + handle.ToString() + ")"); + FileStream f = files[handle]; + + writer.Write(BYTE_SPECIAL); + writer.Write(0); + f.Close(); + files[handle] = null; + } + else + { + // Check if it is a file to dump + foreach (var item in files_request) + { + if (item.Key == fd) + { + FileStream dump_file = item.Value; + if (dump_file == null) + break; + + Log(log, name + " -> dump complete(\"" + Path.GetFileName(dump_file.Name) + "\")"); + + // Close file and remove from request list + dump_file.Close(); + files_request.Remove(fd); + + break; + } + } + + // Send response + writer.Write(BYTE_NORMAL); + } + break; + } + case BYTE_PING: + { + int val1 = reader.ReadInt32(); + int val2 = reader.ReadInt32(); + + Log(log, name + " PING RECEIVED with values : " + val1.ToString() + " - " + val2.ToString()); + break; + } + + case BYTE_LOG_STR: + { + int len_str = reader.ReadInt32(); + string str = reader.ReadString(Encoding.ASCII, len_str - 1); + if (reader.ReadByte() != 0) throw new InvalidDataException(); + + Log(log, name + " LogString =>(\"" + str + "\")"); + break; + } + default: + throw new InvalidDataException(); + } + } + } + } + catch (Exception e) + { + if (log != null) + Log(log, name + " " + e.Message); + else + Console.WriteLine(name + " " + e.Message); + } + finally + { + foreach (var item in files) + { + if (item != null) + item.Close(); + } + foreach (var item in files_request) + { + if (item.Value != null) + item.Value.Close(); + } + + if (log != null) + log.Close(); + } + Console.WriteLine(name + " Exit"); + } + } +} diff --git a/server/src/Properties/AssemblyInfo.cs b/server/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cec5cea --- /dev/null +++ b/server/src/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("cafiine_server")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ChadSoft")] +[assembly: AssemblyProduct("cafiine_server")] +[assembly: AssemblyCopyright("Copyright © ChadSoft 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fc022709-becf-498f-9a2a-dc3543457b0d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/server/src/System/IO/EndianBinaryReader.cs b/server/src/System/IO/EndianBinaryReader.cs new file mode 100644 index 0000000..74b9aad --- /dev/null +++ b/server/src/System/IO/EndianBinaryReader.cs @@ -0,0 +1,644 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.IO +{ + sealed class EndianBinaryReader : IDisposable + { + private bool disposed; + private byte[] buffer; + + private delegate void ArrayReverse(byte[] array, int count); + private static readonly ArrayReverse[] fastReverse = new ArrayReverse[] { null, null, ArrayReverse2, null, ArrayReverse4, null, null, null, ArrayReverse8 }; + + private static Dictionary>> parserCache = new Dictionary>>(); + + public Stream BaseStream { get; private set; } + public Endianness Endianness { get; set; } + public static Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } } + + private bool Reverse { get { return SystemEndianness != Endianness; } } + + public EndianBinaryReader(Stream baseStream) + : this(baseStream, Endianness.BigEndian) + { } + + public EndianBinaryReader(Stream baseStream, Endianness endianness) + { + if (baseStream == null) throw new ArgumentNullException("baseStream"); + if (!baseStream.CanRead) throw new ArgumentException("base stream is not readable.", "baseStream"); + + BaseStream = baseStream; + Endianness = endianness; + } + + ~EndianBinaryReader() + { + Dispose(false); + } + + /// + /// Fills the buffer with bytes bytes, possibly reversing every stride. Bytes must be a multiple of stide. Stide must be 1 or 2 or 4 or 8. + /// + /// + /// + private void FillBuffer(int bytes, int stride) + { + if (buffer == null || buffer.Length < bytes) + buffer = new byte[bytes]; + + for (int i = 0, read = 0; i < bytes; i += read) + { + read = BaseStream.Read(buffer, i, bytes - i); + if (read <= 0) throw new EndOfStreamException(); + } + + if (Reverse) + { + if (fastReverse[stride] != null) + fastReverse[stride](buffer, bytes); + else + for (int i = 0; i < bytes; i += stride) + { + Array.Reverse(buffer, i, stride); + } + } + } + + private static void ArrayReverse2(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 2]; + array[arrayLength - 2] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 2; + } + } + + private static void ArrayReverse4(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 3]; + array[arrayLength - 3] = array[arrayLength - 2]; + array[arrayLength - 2] = temp; + temp = array[arrayLength - 4]; + array[arrayLength - 4] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 4; + } + } + + private static void ArrayReverse8(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 5]; + array[arrayLength - 5] = array[arrayLength - 4]; + array[arrayLength - 4] = temp; + temp = array[arrayLength - 6]; + array[arrayLength - 6] = array[arrayLength - 3]; + array[arrayLength - 3] = temp; + temp = array[arrayLength - 7]; + array[arrayLength - 7] = array[arrayLength - 2]; + array[arrayLength - 2] = temp; + temp = array[arrayLength - 8]; + array[arrayLength - 8] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 8; + } + } + + public byte ReadByte() + { + FillBuffer(1, 1); + + return buffer[0]; + } + + public byte[] ReadBytes(int count) + { + byte[] temp; + + FillBuffer(count, 1); + temp = new byte[count]; + Array.Copy(buffer, 0, temp, 0, count); + return temp; + } + + public sbyte ReadSByte() + { + FillBuffer(1, 1); + + unchecked + { + return (sbyte)buffer[0]; + } + } + + public sbyte[] ReadSBytes(int count) + { + sbyte[] temp; + + temp = new sbyte[count]; + FillBuffer(count, 1); + + unchecked + { + for (int i = 0; i < count; i++) + { + temp[i] = (sbyte)buffer[i]; + } + } + + return temp; + } + + public char ReadChar(Encoding encoding) + { + int size; + + if (encoding == null) throw new ArgumentNullException("encoding"); + + size = GetEncodingSize(encoding); + FillBuffer(size, size); + return encoding.GetChars(buffer, 0, size)[0]; + } + + public char[] ReadChars(Encoding encoding, int count) + { + int size; + + if (encoding == null) throw new ArgumentNullException("encoding"); + + size = GetEncodingSize(encoding); + FillBuffer(size * count, size); + return encoding.GetChars(buffer, 0, size * count); + } + + private static int GetEncodingSize(Encoding encoding) + { + if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII) + return 1; + else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode) + return 2; + + return 1; + } + + public string ReadStringNT(Encoding encoding) + { + string text; + + text = ""; + + do + { + text += ReadChar(encoding); + } while (!text.EndsWith("\0", StringComparison.Ordinal)); + + return text.Remove(text.Length - 1); + } + + public string ReadString(Encoding encoding, int count) + { + return new string(ReadChars(encoding, count)); + } + + public double ReadDouble() + { + const int size = sizeof(double); + FillBuffer(size, size); + return BitConverter.ToDouble(buffer, 0); + } + + public double[] ReadDoubles(int count) + { + const int size = sizeof(double); + double[] temp; + + temp = new double[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToDouble(buffer, size * i); + } + return temp; + } + + public Single ReadSingle() + { + const int size = sizeof(Single); + FillBuffer(size, size); + return BitConverter.ToSingle(buffer, 0); + } + + public Single[] ReadSingles(int count) + { + const int size = sizeof(Single); + Single[] temp; + + temp = new Single[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToSingle(buffer, size * i); + } + return temp; + } + + public Int32 ReadInt32() + { + const int size = sizeof(Int32); + FillBuffer(size, size); + return BitConverter.ToInt32(buffer, 0); + } + + public Int32[] ReadInt32s(int count) + { + const int size = sizeof(Int32); + Int32[] temp; + + temp = new Int32[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToInt32(buffer, size * i); + } + return temp; + } + + public Int64 ReadInt64() + { + const int size = sizeof(Int64); + FillBuffer(size, size); + return BitConverter.ToInt64(buffer, 0); + } + + public Int64[] ReadInt64s(int count) + { + const int size = sizeof(Int64); + Int64[] temp; + + temp = new Int64[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToInt64(buffer, size * i); + } + return temp; + } + + public Int16 ReadInt16() + { + const int size = sizeof(Int16); + FillBuffer(size, size); + return BitConverter.ToInt16(buffer, 0); + } + + public Int16[] ReadInt16s(int count) + { + const int size = sizeof(Int16); + Int16[] temp; + + temp = new Int16[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToInt16(buffer, size * i); + } + return temp; + } + + public UInt16 ReadUInt16() + { + const int size = sizeof(UInt16); + FillBuffer(size, size); + return BitConverter.ToUInt16(buffer, 0); + } + + public UInt16[] ReadUInt16s(int count) + { + const int size = sizeof(UInt16); + UInt16[] temp; + + temp = new UInt16[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToUInt16(buffer, size * i); + } + return temp; + } + + public UInt32 ReadUInt32() + { + const int size = sizeof(UInt32); + FillBuffer(size, size); + return BitConverter.ToUInt32(buffer, 0); + } + + public UInt32[] ReadUInt32s(int count) + { + const int size = sizeof(UInt32); + UInt32[] temp; + + temp = new UInt32[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToUInt32(buffer, size * i); + } + return temp; + } + + public UInt64 ReadUInt64() + { + const int size = sizeof(UInt64); + FillBuffer(size, size); + return BitConverter.ToUInt64(buffer, 0); + } + + public UInt64[] ReadUInt64s(int count) + { + const int size = sizeof(UInt64); + UInt64[] temp; + + temp = new UInt64[count]; + FillBuffer(size * count, size); + + for (int i = 0; i < count; i++) + { + temp[i] = BitConverter.ToUInt64(buffer, size * i); + } + return temp; + } + + private List> GetParser(Type type) + { + List> parser; + + /* A parser describes how to read in a type in an Endian + * appropriate manner. Basically it describes as series of calls to + * the Read* methods above to parse the structure. + * The parser runs through each element in the list in order. If + * the TypeCode is not Empty then it reads an array of values + * according to the integer. Otherwise it skips a number of bytes. */ + + try + { + parser = parserCache[type]; + } + catch (KeyNotFoundException) + { + parser = new List>(); + + if (Endianness != SystemEndianness) + { + int pos, sz; + + pos = 0; + foreach (var item in type.GetFields()) + { + int off = Marshal.OffsetOf(type, item.Name).ToInt32(); + if (off != pos) + { + parser.Add(new Tuple(off - pos, TypeCode.Empty)); + pos = off; + } + switch (Type.GetTypeCode(item.FieldType)) + { + case TypeCode.Byte: + case TypeCode.SByte: + pos += 1; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + pos += 2; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + pos += 4; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + pos += 8; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Object: + if (item.FieldType.IsArray) + { + /* array */ + Type elementType; + MarshalAsAttribute[] attrs; + MarshalAsAttribute attr; + + attrs = (MarshalAsAttribute[])item.GetCustomAttributes(typeof(MarshalAsAttribute), false); + if (attrs.Length != 1) + throw new ArgumentException(String.Format("Field `{0}' is an array without a MarshalAs attribute.", item.Name), "type"); + + attr = attrs[0]; + if (attr.Value != UnmanagedType.ByValArray) + throw new ArgumentException(String.Format("Field `{0}' is not a ByValArray.", item.Name), "type"); + + elementType = item.FieldType.GetElementType(); + switch (Type.GetTypeCode(elementType)) + { + case TypeCode.Byte: + case TypeCode.SByte: + pos += 1 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + pos += 2 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + pos += 4 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + pos += 8 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Object: + /* nested structure */ + for (int i = 0; i < attr.SizeConst; i++) + { + pos += Marshal.SizeOf(elementType); + parser.AddRange(GetParser(elementType)); + } + break; + default: + break; + } + } + else + { + /* nested structure */ + pos += Marshal.SizeOf(item.FieldType); + parser.AddRange(GetParser(item.FieldType)); + } + break; + default: + throw new NotImplementedException(); + } + } + + sz = Marshal.SizeOf(type); + if (sz != pos) + { + parser.Add(new Tuple(sz - pos, TypeCode.Empty)); + } + } + else + { + int sz; + + sz = Marshal.SizeOf(type); + parser.Add(new Tuple(sz, TypeCode.Byte)); + } + parserCache.Add(type, parser); + } + + return parser; + } + + private void RunParser(List> parser, BinaryWriter wr) + { + foreach (var item in parser) + { + /* Assumption: Types of the same size can be interchanged. */ + switch (item.Item2) + { + case TypeCode.Byte: + case TypeCode.SByte: + wr.Write(ReadBytes(item.Item1), 0, item.Item1); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + foreach (var val in ReadInt16s(item.Item1)) + wr.Write(val); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + foreach (var val in ReadInt32s(item.Item1)) + wr.Write(val); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + foreach (var val in ReadInt64s(item.Item1)) + wr.Write(val); + break; + case TypeCode.Empty: + BaseStream.Seek(item.Item1, SeekOrigin.Current); + wr.BaseStream.Seek(item.Item1, SeekOrigin.Current); + break; + default: + throw new NotImplementedException(); + } + } + } + + public object ReadStructure(Type type) + { + List> parser; + object result; + + parser = GetParser(type); + + using (var ms = new MemoryStream()) + { + using (var wr = new BinaryWriter(ms)) + { + RunParser(parser, wr); + } + result = Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(ms.ToArray(), 0), type); + } + return result; + } + + public Array ReadStructures(Type type, int count) + { + List> parser; + Array result; + + parser = GetParser(type); + + result = Array.CreateInstance(type, count); + + using (var ms = new MemoryStream()) + { + using (var wr = new BinaryWriter(ms)) + { + for (int i = 0; i < count; i++) + { + ms.Seek(0, SeekOrigin.Begin); + RunParser(parser, wr); + result.SetValue(Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(ms.ToArray(), 0), type), i); + } + } + } + return result; + } + + public void Close() + { + BaseStream.Close(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + } + + BaseStream = null; + buffer = null; + + disposed = true; + } + } + } + + enum Endianness + { + BigEndian, + LittleEndian, + } +} diff --git a/server/src/System/IO/EndianBinaryWriter.cs b/server/src/System/IO/EndianBinaryWriter.cs new file mode 100644 index 0000000..fbb9180 --- /dev/null +++ b/server/src/System/IO/EndianBinaryWriter.cs @@ -0,0 +1,643 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.IO +{ + sealed class EndianBinaryWriter : IDisposable + { + private bool disposed; + private byte[] buffer; + + private delegate void ArrayReverse(byte[] array, int count); + private static readonly ArrayReverse[] fastReverse = new ArrayReverse[] { null, null, ArrayReverse2, null, ArrayReverse4, null, null, null, ArrayReverse8 }; + + private static Dictionary>> parserCache = new Dictionary>>(); + + public Stream BaseStream { get; private set; } + public Endianness Endianness { get; set; } + public static Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } } + + private bool Reverse { get { return SystemEndianness != Endianness; } } + + public EndianBinaryWriter(Stream baseStream) + : this(baseStream, Endianness.BigEndian) + { } + + public EndianBinaryWriter(Stream baseStream, Endianness endianness) + { + if (baseStream == null) throw new ArgumentNullException("baseStream"); + if (!baseStream.CanWrite) throw new ArgumentException("base stream is not writeable", "baseStream"); + + BaseStream = baseStream; + Endianness = endianness; + } + + ~EndianBinaryWriter() + { + Dispose(false); + } + + private void WriteBuffer(int bytes, int stride) + { + if (Reverse) + { + if (fastReverse[stride] != null) + fastReverse[stride](buffer, bytes); + else + for (int i = 0; i < bytes; i += stride) + { + Array.Reverse(buffer, i, stride); + } + } + + BaseStream.Write(buffer, 0, bytes); + } + + private static void ArrayReverse2(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 2]; + array[arrayLength - 2] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 2; + } + } + + private static void ArrayReverse4(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 3]; + array[arrayLength - 3] = array[arrayLength - 2]; + array[arrayLength - 2] = temp; + temp = array[arrayLength - 4]; + array[arrayLength - 4] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 4; + } + } + + private static void ArrayReverse8(byte[] array, int arrayLength) + { + byte temp; + + while (arrayLength > 0) + { + temp = array[arrayLength - 5]; + array[arrayLength - 5] = array[arrayLength - 4]; + array[arrayLength - 4] = temp; + temp = array[arrayLength - 6]; + array[arrayLength - 6] = array[arrayLength - 3]; + array[arrayLength - 3] = temp; + temp = array[arrayLength - 7]; + array[arrayLength - 7] = array[arrayLength - 2]; + array[arrayLength - 2] = temp; + temp = array[arrayLength - 8]; + array[arrayLength - 8] = array[arrayLength - 1]; + array[arrayLength - 1] = temp; + arrayLength -= 8; + } + } + + private void CreateBuffer(int size) + { + if (buffer == null || buffer.Length < size) + buffer = new byte[size]; + } + + public void Write(byte value) + { + CreateBuffer(1); + buffer[0] = value; + WriteBuffer(1, 1); + } + + public void Write(byte[] value, int offset, int count) + { + CreateBuffer(count); + Array.Copy(value, offset, buffer, 0, count); + WriteBuffer(count, 1); + } + + public void Write(sbyte value) + { + CreateBuffer(1); + unchecked + { + buffer[0] = (byte)value; + } + WriteBuffer(1, 1); + } + + public void Write(sbyte[] value, int offset, int count) + { + CreateBuffer(count); + + unchecked + { + for (int i = 0; i < count; i++) + { + buffer[i] = (byte)value[i + offset]; + } + } + + WriteBuffer(count, 1); + } + + public void Write(char value, Encoding encoding) + { + int size; + + if (encoding == null) throw new ArgumentNullException("encoding"); + + size = GetEncodingSize(encoding); + CreateBuffer(size); + Array.Copy(encoding.GetBytes(new string(value, 1)), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(char[] value, int offset, int count, Encoding encoding) + { + int size; + + if (encoding == null) throw new ArgumentNullException("encoding"); + + size = GetEncodingSize(encoding); + CreateBuffer(size * count); + Array.Copy(encoding.GetBytes(value, offset, count), 0, buffer, 0, count * size); + WriteBuffer(size * count, size); + } + + private static int GetEncodingSize(Encoding encoding) + { + if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII) + return 1; + else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode) + return 2; + + return 1; + } + + public void Write(string value,Encoding encoding, bool nullTerminated) + { + Write(value.ToCharArray(), 0, value.Length, encoding); + if (nullTerminated) + Write('\0', encoding); + } + + public void Write(double value) + { + const int size = sizeof(double); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(double[] value, int offset, int count) + { + const int size = sizeof(double); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(Single value) + { + const int size = sizeof(Single); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(Single[] value, int offset, int count) + { + const int size = sizeof(Single); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(Int32 value) + { + const int size = sizeof(Int32); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(Int32[] value, int offset, int count) + { + const int size = sizeof(Int32); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(Int64 value) + { + const int size = sizeof(Int64); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(Int64[] value, int offset, int count) + { + const int size = sizeof(Int64); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(Int16 value) + { + const int size = sizeof(Int16); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(Int16[] value, int offset, int count) + { + const int size = sizeof(Int16); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(UInt16 value) + { + const int size = sizeof(UInt16); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(UInt16[] value, int offset, int count) + { + const int size = sizeof(UInt16); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(UInt32 value) + { + const int size = sizeof(UInt32); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(UInt32[] value, int offset, int count) + { + const int size = sizeof(UInt32); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void Write(UInt64 value) + { + const int size = sizeof(UInt64); + + CreateBuffer(size); + Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); + WriteBuffer(size, size); + } + + public void Write(UInt64[] value, int offset, int count) + { + const int size = sizeof(UInt64); + + CreateBuffer(size * count); + for (int i = 0; i < count; i++) + { + Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); + } + + WriteBuffer(size * count, size); + } + + public void WritePadding(int multiple, byte padding) + { + int length = (int)(BaseStream.Position % multiple); + + if (length != 0) + while (length != multiple) + { + BaseStream.WriteByte(padding); + length++; + } + } + + public void WritePadding(int multiple, byte padding, long from, int offset) + { + int length = (int)((BaseStream.Position - from) % multiple); + length = (length + offset) % multiple; + + if (length != 0) + while (length != multiple) + { + BaseStream.WriteByte(padding); + length++; + } + } + + private List> GetParser(Type type) + { + List> parser; + + /* A parser describes how to read in a type in an Endian + * appropriate manner. Basically it describes as series of calls to + * the Read* methods above to parse the structure. + * The parser runs through each element in the list in order. If + * the TypeCode is not Empty then it reads an array of values + * according to the integer. Otherwise it skips a number of bytes. */ + + try + { + parser = parserCache[type]; + } + catch (KeyNotFoundException) + { + parser = new List>(); + + if (Endianness != SystemEndianness) + { + int pos, sz; + + pos = 0; + foreach (var item in type.GetFields()) + { + int off = Marshal.OffsetOf(type, item.Name).ToInt32(); + if (off != pos) + { + parser.Add(new Tuple(off - pos, TypeCode.Empty)); + pos = off; + } + switch (Type.GetTypeCode(item.FieldType)) + { + case TypeCode.Byte: + case TypeCode.SByte: + pos += 1; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + pos += 2; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + pos += 4; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + pos += 8; + parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); + break; + case TypeCode.Object: + if (item.FieldType.IsArray) + { + /* array */ + Type elementType; + MarshalAsAttribute[] attrs; + MarshalAsAttribute attr; + + attrs = (MarshalAsAttribute[])item.GetCustomAttributes(typeof(MarshalAsAttribute), false); + if (attrs.Length != 1) + throw new ArgumentException(String.Format("Field `{0}' is an array without a MarshalAs attribute.", item.Name), "type"); + + attr = attrs[0]; + if (attr.Value != UnmanagedType.ByValArray) + throw new ArgumentException(String.Format("Field `{0}' is not a ByValArray.", item.Name), "type"); + + elementType = item.FieldType.GetElementType(); + switch (Type.GetTypeCode(elementType)) + { + case TypeCode.Byte: + case TypeCode.SByte: + pos += 1 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + pos += 2 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + pos += 4 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + pos += 8 * attr.SizeConst; + parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); + break; + case TypeCode.Object: + /* nested structure */ + for (int i = 0; i < attr.SizeConst; i++) + { + pos += Marshal.SizeOf(elementType); + parser.AddRange(GetParser(elementType)); + } + break; + default: + break; + } + } + else + { + /* nested structure */ + pos += Marshal.SizeOf(item.FieldType); + parser.AddRange(GetParser(item.FieldType)); + } + break; + default: + throw new NotImplementedException(); + } + } + + sz = Marshal.SizeOf(type); + if (sz != pos) + { + parser.Add(new Tuple(sz - pos, TypeCode.Empty)); + } + } + else + { + int sz; + + sz = Marshal.SizeOf(type); + parser.Add(new Tuple(sz, TypeCode.Byte)); + } + parserCache.Add(type, parser); + } + + return parser; + } + + private void RunParser(List> parser, BinaryReader rd) + { + foreach (var item in parser) + { + /* Assumption: Types of the same size can be interchanged. */ + switch (item.Item2) + { + case TypeCode.Byte: + case TypeCode.SByte: + Write(rd.ReadBytes(item.Item1), 0, item.Item1); + break; + case TypeCode.Int16: + case TypeCode.UInt16: + for (int i = 0; i < item.Item1; i++) + Write(rd.ReadInt16()); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + for (int i = 0; i < item.Item1; i++) + Write(rd.ReadInt32()); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + for (int i = 0; i < item.Item1; i++) + Write(rd.ReadInt64()); + break; + case TypeCode.Empty: + rd.BaseStream.Seek(item.Item1, SeekOrigin.Current); + BaseStream.Seek(item.Item1, SeekOrigin.Current); + break; + default: + throw new NotImplementedException(); + } + } + } + + public void Write(object structure) + { + List> parser; + Type type; + byte[] data; + + type = structure.GetType(); + parser = GetParser(type); + data = new byte[Marshal.SizeOf(type)]; + + using (var ms = new MemoryStream(data)) + { + using (var rd = new BinaryReader(ms)) + { + Marshal.StructureToPtr(structure, Marshal.UnsafeAddrOfPinnedArrayElement(data, 0), true); + RunParser(parser, rd); + } + } + } + + public void Write(Array structures) + { + List> parser; + Type type; + byte[] data; + + type = structures.GetType().GetElementType(); + parser = GetParser(type); + data = new byte[Marshal.SizeOf(type)]; + + using (var ms = new MemoryStream(data)) + { + using (var rd = new BinaryReader(ms)) + { + foreach (var structure in structures) + { + ms.Seek(0, SeekOrigin.Begin); + Marshal.StructureToPtr(structure, Marshal.UnsafeAddrOfPinnedArrayElement(data, 0), true); + RunParser(parser, rd); + } + } + } + } + + public void Close() + { + BaseStream.Close(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + } + + BaseStream = null; + buffer = null; + + disposed = true; + } + } + } +} diff --git a/server/src/app.config b/server/src/app.config new file mode 100644 index 0000000..49cc43e --- /dev/null +++ b/server/src/app.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/server/src/cafiine_server.v12.suo b/server/src/cafiine_server.v12.suo new file mode 100644 index 0000000..e2e067c Binary files /dev/null and b/server/src/cafiine_server.v12.suo differ diff --git a/server/src/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/server/src/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..814ec97 Binary files /dev/null and b/server/src/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/server/src/obj/x86/Debug/saviine_server.csproj.FileListAbsolute.txt b/server/src/obj/x86/Debug/saviine_server.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..1e48085 --- /dev/null +++ b/server/src/obj/x86/Debug/saviine_server.csproj.FileListAbsolute.txt @@ -0,0 +1,6 @@ +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\bin\saviine_server.exe.config +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\bin\saviine_server.exe +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\bin\saviine_server.pdb +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\obj\x86\Debug\saviine_server.csprojResolveAssemblyReference.cache +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\obj\x86\Debug\saviine_server.exe +G:\Programmieren\libwiiu-master\saviine\saviine\server\src\obj\x86\Debug\saviine_server.pdb diff --git a/server/src/obj/x86/Debug/saviine_server.csprojResolveAssemblyReference.cache b/server/src/obj/x86/Debug/saviine_server.csprojResolveAssemblyReference.cache new file mode 100644 index 0000000..62c1799 Binary files /dev/null and b/server/src/obj/x86/Debug/saviine_server.csprojResolveAssemblyReference.cache differ diff --git a/server/src/obj/x86/Debug/saviine_server.exe b/server/src/obj/x86/Debug/saviine_server.exe new file mode 100644 index 0000000..dab8131 Binary files /dev/null and b/server/src/obj/x86/Debug/saviine_server.exe differ diff --git a/server/src/obj/x86/Debug/saviine_server.pdb b/server/src/obj/x86/Debug/saviine_server.pdb new file mode 100644 index 0000000..fba0c85 Binary files /dev/null and b/server/src/obj/x86/Debug/saviine_server.pdb differ diff --git a/server/src/saviine_server.csproj b/server/src/saviine_server.csproj new file mode 100644 index 0000000..f5cb490 --- /dev/null +++ b/server/src/saviine_server.csproj @@ -0,0 +1,94 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {84FB17D5-D67B-4B9E-9041-00424036BF2E} + Exe + Properties + saviine_server + saviine_server + v4.0 + Client + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + x86 + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4 Client Profile %28x86 und x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + \ No newline at end of file diff --git a/server/src/saviine_server.csproj.user b/server/src/saviine_server.csproj.user new file mode 100644 index 0000000..862620d --- /dev/null +++ b/server/src/saviine_server.csproj.user @@ -0,0 +1,13 @@ + + + + publish\ + + + + + + de-DE + false + + \ No newline at end of file diff --git a/server/src/saviine_server.sln b/server/src/saviine_server.sln new file mode 100644 index 0000000..a495a42 --- /dev/null +++ b/server/src/saviine_server.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "saviine_server", "saviine_server.csproj", "{84FB17D5-D67B-4B9E-9041-00424036BF2E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Debug|x86.ActiveCfg = Debug|x86 + {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Debug|x86.Build.0 = Debug|x86 + {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Release|x86.ActiveCfg = Release|x86 + {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/server/src/saviine_server.suo b/server/src/saviine_server.suo new file mode 100644 index 0000000..26dbb3d Binary files /dev/null and b/server/src/saviine_server.suo differ diff --git a/server/src/saviine_server.v12.suo b/server/src/saviine_server.v12.suo new file mode 100644 index 0000000..59e1a3f Binary files /dev/null and b/server/src/saviine_server.v12.suo differ