// by oggzee #include #include #include #include #include #include #include #include #include #include #include #include #include #include "disc.h" #include "fat.h" #include "cache.h" #include "gui.h" #include "menu.h" #include "restart.h" #include "sys.h" #include "util.h" #include "utils.h" #include "video.h" #include "wbfs.h" #include "wpad.h" #include "patchcode.h" #include "cfg.h" #include "http.h" #include "dns.h" #include "wdvd.h" #include "music.h" #include "subsystem.h" #include "net.h" #include "menu.h" #include "gettext.h" //////////////////////////////////////// // // Cheats // //////////////////////////////////////// bool get_line_buf(char **buf, char *line, int linesize) { char *p, *nl; int len; *line = 0; if (buf == NULL) return false; if (*buf == NULL) return false; if (**buf == 0) return false; p = *buf; nl = strchr(p, '\n'); // find LF if (nl == NULL) { len = strlen(p); *buf = NULL; } else { len = nl - p; *buf = nl + 1; if (**buf == 0) *buf = NULL; } if (len >= linesize) len = linesize - 1; strcopy(line, p, len+1); // remove any CR in case it's a msdos CRLF format len = strlen(line); if (len > 0 && line[len-1] == '\r') line[len-1] = 0; return true; } #define CHEAT_MAX_TITLE 40 #define CHEAT_MAX_NOTES 3 #define CHEAT_MAX_LINES 3000 #define CODE_LINE_LEN 18 #define CHEAT_MAX 512 struct Cheat { char title[CHEAT_MAX_TITLE]; int num_codes; int line_idx; // index to code line int num_notes; char note[CHEAT_MAX_NOTES][CHEAT_MAX_TITLE]; bool enabled; bool editable; }; struct Cheats { char id[8]; char title[CHEAT_MAX_TITLE]; int num_lines; char line[CHEAT_MAX_LINES][CODE_LINE_LEN]; int num_cheats; struct Cheat cheat[CHEAT_MAX]; }; struct Cheats cheats; int line_buf_count; char *line_buf; char line[200]; bool get_line() { bool ret; line_buf_count++; ret = get_line_buf(&line_buf, D_S(line)); //printf("%d %s\n", line_buf_count, line); return ret; } // sample: //P2 No Laps (Finish right away) //48000000 809BD730 [memorris] //DE000000 80008180 bool is_code(char *line) { int i; if (strlen(line) < 17) return false; if (strlen(line) > 17 && line[17] != ' ') return false; if (line[8] != ' ') return false; // check if address is valid for (i=0; i<8; i++) { if (!ISXDIGIT(line[i])) return false; } // check if value is hex for (i=9; i<17; i++) { if (!ISALNUM(line[i])) return false; } return true; } // sample: //14000000 000000XX bool is_editable(char *line) { int i; if (!is_code(line)) return false; for (i=9; i<17; i++) { // is hex digit? if (!ISXDIGIT(line[i])) return true; } return false; } bool parse_cheats(char *buf) { struct Cheat *cur_cheat; memset(&cheats, 0, sizeof(cheats)); line_buf_count = 0; line_buf = buf; // first line if (!get_line()) goto err; // remove utf8 bom if (memcmp(line, "\xEF\xBB\xBF", 3) == 0) { memmove(line, line+3, strlen(line+3)+1); } // game id if (strlen(line) < 4 || strlen(line) > 6) goto err; STRCOPY(cheats.id, line); // game title if (!get_line()) goto err; if (strlen(line) == 0) goto err; STRCOPY(cheats.title, line); // empty line if (!get_line()) goto err; if (strlen(line) > 0) goto err; // loop cheats for (;;) { // cheat title if (!get_line()) break; if (strlen(line) == 0) return false; if (cheats.num_cheats >= CHEAT_MAX) { printf(gt("Too many cheats! (%d)"), cheats.num_cheats); printf("\n"); goto err2; } cheats.num_cheats++; cur_cheat = &cheats.cheat[cheats.num_cheats-1]; STRCOPY(cur_cheat->title, line); // loop codes for (;;) { if (!get_line()) break; if (strlen(line) == 0) break; // empty line = end if (is_code(line)) { // it's a code. if (cheats.num_lines >= CHEAT_MAX_LINES) { printf(gt("Too many code lines!")); printf("\n"); goto err2; } cheats.num_lines++; STRCOPY(cheats.line[cheats.num_lines-1], line); if (cur_cheat->num_codes == 0) { cur_cheat->line_idx = cheats.num_lines - 1; } cur_cheat->num_codes++; if (is_editable(line)) { cur_cheat->editable = true; } } else { // it's a note. for (;;) { cur_cheat->num_notes++; if (cur_cheat->num_notes <= CHEAT_MAX_NOTES) { STRCOPY(cur_cheat->note[cur_cheat->num_notes-1], line); } else { // ignore the rest of notes } if (!get_line()) break; if (strlen(line) == 0) break; // empty line = end } break; } } } return true; err: printf(gt("Unknown syntax!")); printf("\n"); printf("%d: '%s'\n", line_buf_count, line); err2: printf(gt("Press any button...")); printf("\n"); Wpad_WaitButtons(); // reset cheats on error. memset(&cheats, 0, sizeof(cheats)); return false; } int Load_Cheats_TXT(char *id) { char filepath[200]; char *buf = NULL; int size = 0; bool ret; // reset all to 0 memset(&cheats, 0, sizeof(cheats)); snprintf(D_S(filepath), "%s/codes/%.6s.txt", USBLOADER_PATH, id); size = Fat_ReadFile(filepath, (void*)&buf); if (size <= 0 || buf == NULL) return 2; // no file dbg_printf("\n%s : %d\n", filepath, size); // null terminate char *newbuf; newbuf = realloc(buf, size+4); if (newbuf) { newbuf[size] = 0; buf = (void*)newbuf; } else { SAFE_FREE(buf); return 1; } // parse ret = parse_cheats(buf); SAFE_FREE(buf); if (!ret) return 1; // parse error if (strncmp(id, cheats.id, strlen(cheats.id)) != 0) return 1; return 0; // ok } int Save_Cheats_GCT(char *id) { char filepath[200]; char gct_head[] = { 0x00, 0xD0, 0xC0, 0xDE, 0x00, 0xD0, 0xC0, 0xDE }; char gct_tail[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int i, j, k, count; struct Cheat *cheat = NULL; FILE *f; count = 0; for (i=0; ienabled) { for (j=0; jnum_codes; j++) { char *cp; unsigned int ci = 0; unsigned char c = 0; cp = cheats.line[cheat->line_idx + j]; //printf("[%d %d] %s\n ", i, j, cp); for (k=0; k<8; k++) { if (k == 4) cp++; // skip space sscanf(cp, "%2x", &ci); c = ci; //printf("%02x ", c); fwrite(&c, 1, 1, f); cp += 2; } //printf("\n"); } } } // gct tail fwrite(gct_tail, 1, sizeof(gct_tail), f); fclose(f); printf_(gt("Done.")); printf("\n"); sleep(2); //Wpad_WaitButtons(); return 0; // ok } bool Download_Cheats_TXT(char *id) { char filepath[200]; //char *url_base = "http://www.usbgecko.com/codes/codes"; char *url_base = "http://www.geckocodes.org/codes"; char url[200]; struct block file; FILE *f; file.data = NULL; DefaultColor(); printf("\n"); printf_(gt("Downloading cheats...")); printf("\n"); extern bool Init_Net(); if (!Init_Net()) goto err; // 6 letters ID //snprintf(D_S(url), "%s/%c/%.6s.txt", url_base, id[0], id); snprintf(D_S(url), "%s/R/%.6s.txt", url_base, id); dbg_printf("url: %s\n", url); file = downloadfile_noreferer(url); if (file.data == NULL || file.size == 0) { snprintf(D_S(url), "%s/G/%.6s.txt", url_base, id); dbg_printf("url: %s\n", url); file = downloadfile_noreferer(url); if (file.data == NULL || file.size == 0) { // 4 letters ID snprintf(D_S(url), "%s/%c/%.4s.txt", url_base, id[0], id); dbg_printf("url: %s\n", url); file = downloadfile_noreferer(url); if (file.data == NULL || file.size == 0) { printf_(gt("Error downloading.")); printf("\n"); goto err; } } } printf_(gt("Saving cheats...")); printf("\n"); snprintf(D_S(filepath), "%s/codes", USBLOADER_PATH); mkpath(filepath, 0777); snprintf(D_S(filepath), "%s/codes/%.6s.txt", USBLOADER_PATH, id); printf_("%s\n", filepath); f = fopen(filepath, "wb"); if (!f) { printf("\n"); printf_(gt("Error opening: %s"), filepath); printf("\n"); goto err; } fwrite(file.data, 1, file.size, f); fclose(f); printf_(gt("OK")); printf("\n"); SAFE_FREE(file.data); sleep(2); return true; err: printf("\n"); printf(gt("Press any button...")); printf("\n"); Wpad_WaitButtons(); SAFE_FREE(file.data); return false; } void print_game_info(struct discHdr *header, int cols) { int len; len = cols - strlen(CFG.menu_plus_s) - 10; printf_(""); printf("(%.6s) ", header->id); printf("%.*s\n", len, get_title(header)); } /* Ocarina Cheat Manager RHAP Wii Play Cheats: 20 found / no file / parse error