diff options
author | Kitty Draper | 2011-03-05 21:39:25 -0500 |
---|---|---|
committer | Kitty Draper | 2011-03-05 21:39:25 -0500 |
commit | d40ae99422e118188a7f48055dc340c6aca022aa (patch) | |
tree | 83ab93f49fd9e66e43bcd824091ae1dbcaa0c173 /source/nds/gcheat.c | |
download | snesemu-d40ae99422e118188a7f48055dc340c6aca022aa.tar.gz snesemu-d40ae99422e118188a7f48055dc340c6aca022aa.tar.bz2 snesemu-d40ae99422e118188a7f48055dc340c6aca022aa.zip |
first commit
Diffstat (limited to 'source/nds/gcheat.c')
-rw-r--r-- | source/nds/gcheat.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/source/nds/gcheat.c b/source/nds/gcheat.c new file mode 100644 index 0000000..062ce9d --- /dev/null +++ b/source/nds/gcheat.c @@ -0,0 +1,527 @@ +/* gcheat.c + * + * Copyright (C) 2010 dking <dking024@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licens e as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "string.h" +#include "fs_api.h" +#include "ds2_malloc.h" +#include "gcheat.h" +#include "charsets.h" + +#define MAX_SFCCHEAT_NAME 24 + + +//GCHEAT_STRUCT gcheat[MAX_CHEATS]; +unsigned int g_cheat_cell_num; +unsigned int g_cheat_num; +
+#define SKIP_SPACE(pt) while(' ' == *pt) pt++
+ +static unsigned char* check_is_cht(unsigned char *str) +{ + unsigned char *pt, *pt1; + + if(*str == '\0') return NULL; + + pt = str; + while(*pt == ' ') pt++; //Skip leading space + if(*pt != '[') return NULL; //valid entry should be:[string] + + pt1 = strrchr(str, ']'); + if(pt1 == NULL) return NULL; + + while(*(--pt1) == ' '); + *(pt1+1) = '\0'; //Cut trailing space between string and ']' + + while(*(++pt) == ' '); //Cut space between '[' and string + + return pt; +} + +static unsigned int sscanf_hex_value(unsigned char* str, unsigned int *value) +{ + unsigned char *pt; + unsigned int tmp; + unsigned char ch; + unsigned int len; + + pt = str; + len = 0; + tmp = 0; + while(*pt && len < 8) + { + ch = *pt; + if(ch >= 'a' && ch <= 'f') ch = ch - 'a' + 0xa; + else if(ch >= 'A' && ch <= 'F') ch = ch - 'A' + 0xa; + else if(ch >= '0' && ch <= '9') ch = ch - '0'; + else if(ch == ' ') continue; + else break; + + tmp = (tmp << 4) | ch; + pt++; + len += 1; + } + + *value = tmp; + return len; +} + +/* +* Convert the src string to UTF8 coding dst string, and cut to length +*/ +int string2utf8(unsigned char *src, unsigned char* dst, unsigned int length) +{ + unsigned char *pt; + unsigned char ch; + unsigned short ucode; + unsigned int type; + unsigned int len; + + len = 0; + type = 0; + pt = src; + while(*pt) + { + pt = utf8decode(pt, &ucode); + if(ucode < 0x4e00) { + if(ucode == 0 || ucode > 0x7F) { + type = 1; + break; + } + } else if(ucode > 0x9FCF) { + type = 1; + break; + } + else + len++; + + if(len >= 3) break; //There is enough UTF8, so it is, to save time(>_*) + } + + if(type == 0) //UTF8 + { + while(*src) + { + ch = *src++; + *dst++ = ch; + + if(ch < 0x80) { + if(length > 1) length -= 1; + else break; + } else if (ch < 0xe0) { /* U-00000080 - U-000007FF, 2 bytes */ + if(length > 2) length -= 2; + else break;
+ *dst++ = *src++;
+ } else if (ch < 0xf0) { /* U-00000800 - U-0000FFFF, 3 bytes */ + if(length > 3) length -= 3; + else break; + *dst++ = *src++;
+ *dst++ = *src++;
+ } else if (ch < 0xf5) { /* U-00010000 - U-001FFFFF, 4 bytes */ + if(length > 4) length -= 4; + else break; + *dst++ = *src++;
+ *dst++ = *src++; + *dst++ = *src++;
+ } else {
+ break;
+ } + } + *dst = '\0'; + } + else //assume it is GBK code + { + //GBK to UTF8 + while(*src) + { + ch = *src; + if(ch < 0x80) + { + if(length > 1) length -= 1; + else break; + + *dst++= ch; + src ++; + } + else + { + ucode = charsets_gbk_to_ucs(src); + + if (ucode < 0x800) //2 bytes + { + if(length > 2) length -= 2; + else break; + + *dst++ = 0xC0 | ((ucode >> 6) & 0x1F); + *dst++ = 0x80 | (ucode & 0x3F); + } + else //3 bytes + { + if(length > 3) length -= 3; + else break; + + *dst++ = 0xE0 | (ucode >> 12); + *dst++ = 0x80 | ((ucode >>6) & 0x3F); + *dst++ = 0x80 | (ucode & 0x3F); + } + + src += 2; + } + } + *dst = '\0'; + } + + return 0; +} + +int load_cheatname(const char* filename, unsigned int string_num, unsigned int string_len, MSG_TABLE* mssg_table) +{ + FILE *fp; + unsigned char current_line[256]; + unsigned char current_line_tmp[256];
+ int len, m; + unsigned char** indexp; + unsigned char* msg; + unsigned char* pt; + + mssg_table->msg_index = (unsigned char**)malloc(string_num*4); + if(NULL == mssg_table->msg_index) + return -1; + + string_len = string_len + string_len/2; + mssg_table->msg_pool = (unsigned char*)malloc((string_len+31)&(~31)); + if(NULL == mssg_table->msg_pool) { + free((void*)mssg_table->msg_index); + return -1; + } + + fp = fopen(filename, "r"); + if(fp == NULL) { + free((void*)mssg_table->msg_index); + free((void*)mssg_table->msg_pool); + return -1; + } + + len = 0; + m= 0; + indexp = mssg_table->msg_index; + msg = mssg_table->msg_pool; + while(fgets(current_line, 256, fp))
+ { + unsigned int str_len; + + if((pt = check_is_cht(current_line)) != NULL) + { + if(!strcasecmp(pt, "gameinfo")) + continue; + + string2utf8(pt, current_line_tmp, 255); + + str_len = strlen(current_line_tmp); + strncpy(msg+len, current_line_tmp, str_len); + + indexp[m++] = msg+len; + len += str_len; + msg[len] = '\0'; + len += 1; + + if(len >= string_len) break; + if(m >= string_num) break; + + while(fgets(current_line, 256, fp)) + { + str_len = strlen(current_line); + if(str_len < 4) break; + + if((pt = strchr(current_line, '=')) == NULL) //valid cheat item + break; + + *pt = '\0'; + pt = current_line; + + string2utf8(pt, current_line_tmp, 255); + + str_len = strlen(current_line_tmp); + strncpy(msg+len, current_line_tmp, str_len); + + indexp[m++] = msg+len; + len += str_len; + msg[len] = '\0'; + len += 1; + + if(len >= string_len) break; + if(m >= string_num) break; + } + + if(len >= string_len) break; + if(m >= string_num) break; + }
+ }
+ + mssg_table -> msg_num = m;
+ fclose(fp); + +#if 0 +cprintf("string_len %d; len %d\n", string_len, len); +for(m= 0; m<mssg_table -> msg_num; m++) +{ +cprintf("msg%d:%s\n", m, indexp[m]); +} +#endif + + return 0; +} + +#define MAX_CHEAT_DATE_LEN (MAX_SFCCHEAT_NAME/2) //other part hold the saved data +
+/* +* Load cheat file +*/ +int load_cheatfile(const char* filename, unsigned int *string_num, unsigned int *string_len, + GCHEAT_STRUCT *gcheat)
+{
+ FILE *cheats_file;
+ unsigned char current_line[256]; + unsigned char current_line_tmp[256]; + unsigned int current_line_len; + unsigned char *pt;
+ int gcheat_num; +
+ unsigned int str_num; + unsigned int str_len; + unsigned int cheat_cell_num; + int flag; +
+ cheats_file = fopen(filename, "r"); + if(NULL == cheats_file) + return -1;
+ g_cheat_cell_num = 0; + g_cheat_num = 0; + cheat_cell_num = 0; + gcheat_num = 0; + str_num = 0; + str_len = 0; + flag = 0; + + while(fgets(current_line, 256, cheats_file))
+ { + if((pt = check_is_cht(current_line)) == NULL) //Check valid cht cheat + continue; + + if(!strcasecmp(pt, "gameinfo")) //maybe file end + continue; + + gcheat[gcheat_num].name_id = str_num; + gcheat[gcheat_num].item_id = cheat_cell_num; + gcheat[gcheat_num].item_num = 0; + + string2utf8(pt, current_line_tmp, CHEAT_NAME_LENGTH); + strcpy(gcheat[gcheat_num].name_shot, current_line_tmp); //store a cut name shot + //Initialize other parameter of gcheat + gcheat[gcheat_num].active = 0; + gcheat[gcheat_num].sub_active = 0; + + current_line_len = strlen(pt); + str_len += current_line_len +1; + str_num++; + + //Cheat items + while(fgets(current_line, 256, cheats_file) != NULL) + { + if(strlen(current_line) < 4) + break; + + if((pt = strchr(current_line, '=')) == NULL) //No valid content + break; + + //one sub item each pass + unsigned int first_part; //first part of a cheat item + unsigned int first_part_id; + unsigned int sub_part_id; + unsigned int hex_len; + + unsigned int cheat_addr; + unsigned char cheat_dat[MAX_CHEAT_DATE_LEN]; + unsigned int cheat_dat_len; + unsigned int str_num_saved; + + str_num_saved = str_num; + str_len += pt - current_line +1; + str_num++; + + first_part = 1; + first_part_id = cheat_cell_num; + sub_part_id = 0; + + //skip name part + pt += 1; + current_line_len = strlen(pt); + + //data part + while(1) + { + //fill current_line buffer as full as possible + if(current_line_len < (MAX_CHEAT_DATE_LEN*3+8)) + { //the data length can fill a cheat cell + if(NULL == strchr(pt, 0x0A)) { //this line not end + memmove(current_line, pt, current_line_len+1); + fgets(current_line+current_line_len, 256-current_line_len, cheats_file); + pt = current_line; + current_line_len = strlen(pt); + } + } +#if 0 +cprintf("------\n"); +cprintf("new %d:[%s]\n", current_line_len, pt); +dump_mem(pt, strlen(pt)); +cprintf("\n------\n"); +#endif + //get address + if(first_part) + { + hex_len = sscanf_hex_value(pt, &cheat_addr); + if(0 == hex_len) { + goto load_cheatfile_error; + } + + pt += hex_len; + current_line_len -= hex_len +1; + // strict to follow the formate + if(',' != *pt++ || '\0' == *pt || 0x0D == *pt || 0x0A == *pt) { + goto load_cheatfile_error; + } + + if(cheat_addr < 0x10000) + cheat_addr |= 0x7e0000; + else { + cheat_addr &= 0xffff; + cheat_addr |= 0x7f0000; + } + } + + //get data + unsigned int tmp, m; + + m = 0; + cheat_dat_len = 0; + while(m++ < MAX_CHEAT_DATE_LEN) + { + hex_len = sscanf_hex_value(pt, &tmp); + if(0 == hex_len) break; + + cheat_dat[cheat_dat_len++] = (unsigned char)tmp; + + pt += hex_len; + current_line_len -= hex_len +1; + if(',' == *pt) pt++; + } + + //In first part, get data error + if(0 == cheat_dat_len) { + if(0 == sub_part_id) + goto load_cheatfile_error; + } + else { + //record data + flag = S9xAddCheat_ex(cheat_addr, cheat_dat, cheat_dat_len, cheat_cell_num++, sub_part_id++, str_num_saved); + if(0 != flag) { + cheat_cell_num -= sub_part_id; + break; + } + } + + if(0 == *pt || 0x0D == *pt || 0x0A == *pt) break; //a line over + + first_part = 0; + if(';' == *pt) first_part = 1, pt += 1; //other address of the cheat cell + else cheat_addr += cheat_dat_len; //more data + } //data part + + //have no enough cheat_cell struct to store cheat + if(0 != flag) break; + + S9xAddCheat_ov(first_part_id, sub_part_id); + gcheat[gcheat_num].item_num += 1; + } //Cheat items + + if(0 != flag) break; + + gcheat_num += 1; + if(gcheat_num >= MAX_CHEATS) + break; + }
+ + g_cheat_cell_num = cheat_cell_num; + g_cheat_num = gcheat_num; + *string_num = str_num; + *string_len = str_len; + fclose(cheats_file); + +#if 0 +cprintf("g_cheat_num %d; g_cheat_cell_num %d\n", g_cheat_num, g_cheat_cell_num); + +int i; +for(i= 0; i < g_cheat_cell_num; i++) +S9x_dumpcheat(i); + +for(i= 0; i < g_cheat_num; i++) +{ + cprintf("cheat %d\n", i); + cprintf("item num %d; item id %d\n", gcheat[i].item_num, gcheat[i].item_id); +} +#endif + + return 0; + +load_cheatfile_error:
+ fclose(cheats_file); + return -1;
+}
+ +void gcheat_Managment(GCHEAT_STRUCT *gcheat) +{ + unsigned int i, enable, m, en_flag; + unsigned int active, item_id, sub_active, item_num; + + //no cheat + if(0 == g_cheat_num || 0 == g_cheat_cell_num) { + S9xCheat_Disable(); + return; + } + + enable = 0; + for(i = 0; i < g_cheat_num; i++) + { + active = gcheat[i].active & 0x1; + item_id = gcheat[i].item_id; + item_num = gcheat[i].item_num; + sub_active = gcheat[i].sub_active; + + for(m = 0; m < item_num; m++) + { + en_flag = sub_active == m ? active : 0; + S9xCheat_switch(item_id, m, en_flag); + } + + if(active) enable = 1; + } + + if(enable) + S9xCheat_Enable(); +} + |