/* Load game information from XML - Lustar - Mini-XML by Michael Sweet - MiniZip adapted by Tantric */ #include #include #include "settings/CSettings.h" #include "xml/xml.h" extern "C" { extern void title_set(char *id, char *title); extern char* trimcopy(char *dest, char *src, int size); extern char game_partition[6]; } /* config */ static bool xmldebug = false; static char xmlcfg_filename[100] = "wiitdb"; static int xmlmaxsize = 1572864; struct gameXMLinfo gameinfo; struct gameXMLinfo gameinfo_reset; static char langlist[11][22] = { { "Console Default" }, { "Japanese" }, { "English" }, { "German" }, { "French" }, { "Spanish" }, { "Italian" }, { "Dutch" }, { "S. Chinese" }, { "T. Chinese" }, { "Korean" } }; static char langcodes[11][5] = { { "" }, { "JA" }, { "EN" }, { "DE" }, { "FR" }, { "ES" }, { "IT" }, { "NL" }, { "ZHCN" }, // People's Republic of China { "ZHTW" }, // Taiwan { "KO" } }; static char element_text[5000]; static mxml_node_t *nodetree = NULL; static mxml_node_t *nodedata = NULL; static mxml_node_t *nodeid = NULL; static mxml_node_t *nodeidtmp = NULL; static mxml_node_t *nodefound = NULL; static mxml_index_t *nodeindex = NULL; static mxml_index_t *nodeindextmp = NULL; int xmlloadtime = 0; char * get_nodetext(mxml_node_t *node, char *buffer, int buflen); bool xml_loaded = false; /* load renamed titles from proper names and game info XML, needs to be after cfg_load_games */ bool OpenXMLDatabase(char* xmlfilepath, char* argdblang, bool argJPtoEN, bool openfile, bool loadtitles, bool keepopen) { if (!xml_loaded) { bool opensuccess = false; char pathname[200]; snprintf(pathname, sizeof(pathname), "%s", xmlfilepath); if (xmlfilepath[strlen(xmlfilepath) - 1] != '/') snprintf(pathname, sizeof(pathname), "%s/", pathname); snprintf(pathname, sizeof(pathname), "%s%s_%s.zip", pathname, xmlcfg_filename, game_partition); if (openfile) opensuccess = OpenXMLFile(pathname); if (!opensuccess) { snprintf(pathname, sizeof(pathname), "%s", xmlfilepath); if (xmlfilepath[strlen(xmlfilepath) - 1] != '/') snprintf(pathname, sizeof(pathname), "%s/", pathname); snprintf(pathname, sizeof(pathname), "%swiitdb.zip", pathname); if (openfile) opensuccess = OpenXMLFile(pathname); } if (!opensuccess && openfile) { CloseXMLDatabase(); return false; } if (loadtitles) LoadTitlesFromXML(argdblang, argJPtoEN); if (!keepopen) CloseXMLDatabase(); } else { if (loadtitles) LoadTitlesFromXML(argdblang, argJPtoEN); if (!keepopen) CloseXMLDatabase(); } return true; } void CloseXMLDatabase() { /* free memory */ if (xml_loaded) { mxmlDelete(nodedata); mxmlDelete(nodetree); xml_loaded = false; } } void GetTextFromNode(mxml_node_t *currentnode, mxml_node_t *topnode, const char *nodename, const char *attributename, char *value, int descend, char *dest, int destsize) { *element_text = 0; nodefound = mxmlFindElement(currentnode, topnode, nodename, attributename, value, descend); if (nodefound != NULL) { if (attributename != NULL) { strlcpy(dest, mxmlElementGetAttr(nodefound, attributename), destsize); } else { get_nodetext(nodefound, element_text, sizeof(element_text)); strlcpy(dest, element_text, destsize); } } else { strcpy(dest, ""); } } bool OpenXMLFile(char *filename) { //if (xmldebug) dbg_time1(); if (xml_loaded) return false; gameinfo = gameinfo_reset; nodedata = NULL; nodetree = NULL; nodeid = NULL; nodeidtmp = NULL; nodefound = NULL; char* strresult = strstr(filename, ".zip"); if (strresult == NULL) { /* Load XML file */ FILE *filexml; filexml = fopen(filename, "rb"); if (!filexml) return false; nodetree = mxmlLoadFile(NULL, filexml, MXML_OPAQUE_CALLBACK); fclose(filexml); } else { /* load zipped XML file */ unzFile unzfile = unzOpen(filename); if (unzfile == NULL) return false; unzOpenCurrentFile(unzfile); unz_file_info zipfileinfo; unzGetCurrentFileInfo(unzfile, &zipfileinfo, NULL, 0, NULL, 0, NULL, 0); int zipfilebuffersize = zipfileinfo.uncompressed_size; if (zipfilebuffersize >= xmlmaxsize) { unzCloseCurrentFile(unzfile); unzClose(unzfile); return false; } char * zipfilebuffer = (char *) malloc(zipfilebuffersize); memset(zipfilebuffer, 0, zipfilebuffersize); if (zipfilebuffer == NULL) { unzCloseCurrentFile(unzfile); unzClose(unzfile); return false; } unzReadCurrentFile(unzfile, zipfilebuffer, zipfilebuffersize); unzCloseCurrentFile(unzfile); unzClose(unzfile); nodetree = mxmlLoadString(NULL, zipfilebuffer, MXML_OPAQUE_CALLBACK); free(zipfilebuffer); } if (nodetree == NULL) return false; nodedata = mxmlFindElement(nodetree, nodetree, "datafile", NULL, NULL, MXML_DESCEND); if (nodedata == NULL) { return false; } else { //if (xmldebug) xmlloadtime = dbg_time2(NULL); xml_loaded = true; return true; } } char *GetLangSettingFromGame(char *gameid) { int langcode; struct Game_CFG *game_cfg = NULL; game_cfg = CFG_get_game_opt((u8*) gameid); if (game_cfg) { langcode = game_cfg->language; } else { //langcode = CFG.language; // for Configurable Loader langcode = Settings.language; // for Loader GX } char *langtxt = langlist[langcode]; return langtxt; } /* convert language text into ISO 639 two-letter language code (+ZHTW/ZHCN) */ const char *ConvertLangTextToCode(char *languagetxt) { // do not convert if languagetext seems to be a language code (can be 2 or 4 letters) if (strlen(languagetxt) <= 4) return languagetxt; int i; for (i = 0; i <= 10; i++) { if (!strcasecmp(languagetxt, langlist[i])) // case insensitive comparison return langcodes[i]; } return ""; } char ConvertRatingToIndex(char *ratingtext) { int type = -1; if (!strcmp(ratingtext, "CERO")) { type = 0; } if (!strcmp(ratingtext, "ESRB")) { type = 1; } if (!strcmp(ratingtext, "PEGI")) { type = 2; } return type; } void ConvertRating(char *ratingvalue, char *fromrating, const char *torating, char *destvalue, int destsize) { if (!strcmp(fromrating, torating)) { strlcpy(destvalue, ratingvalue, destsize); return; } strcpy(destvalue, ""); int type = -1; int desttype = -1; type = ConvertRatingToIndex(fromrating); desttype = ConvertRatingToIndex((char *) torating); if (type == -1 || desttype == -1) return; /* rating conversion table */ /* the list is ordered to pick the most likely value first: */ /* EC and AO are less likely to be used so they are moved down to only be picked up when converting ESRB to PEGI or CERO */ /* the conversion can never be perfect because ratings can differ between regions for the same game */ char ratingtable[12][3][5] = { { { "A" }, { "E" }, { "3" } }, { { "A" }, { "E" }, { "4" } }, { { "A" }, { "E" }, { "6" } }, { { "A" }, { "E" }, { "7" } }, { { "A" }, { "EC" }, { "3" } }, { { "A" }, { "E10+" }, { "7" } }, { { "B" }, { "T" }, { "12" } }, { { "D" }, { "M" }, { "18" } }, { { "D" }, { "M" }, { "16" } }, { { "C" }, { "T" }, { "16" } }, { { "C" }, { "T" }, { "15" } }, { { "Z" }, { "AO" }, { "18" } }, }; int i; for (i = 0; i <= 11; i++) { if (!strcmp(ratingtable[i][type], ratingvalue)) { strlcpy(destvalue, ratingtable[i][desttype], destsize); return; } } } void LoadTitlesFromXML(char *langtxt, bool forcejptoen) /* langtxt: set to "English","French","German", to force language for all titles, or "" to load title depending on each game's setting */ /* forcejptoen: set to true to load English title instead of Japanese title when game is set to Japanese */ { if (nodedata == NULL) return; bool forcelang = false; if (strcmp(langtxt, "")) forcelang = true; char langcode[10] = ""; if (forcelang) strcpy(langcode, ConvertLangTextToCode(langtxt)); /* convert language text into ISO 639 two-letter language code */ /* create index of elements */ nodeindex = mxmlIndexNew(nodedata, "id", NULL); nodeid = mxmlIndexReset(nodeindex); *element_text = 0; char id_text[10]; char title_text[200] = ""; char title_text_EN[200] = ""; /* search index of id elements, load all id/titles text */ while (nodeid != NULL) { nodeid = mxmlIndexFind(nodeindex, "id", NULL); if (nodeid != NULL) { strcpy(title_text, ""); strcpy(title_text_EN, ""); get_nodetext(nodeid, element_text, sizeof(element_text)); snprintf(id_text, 7, "%s", element_text); // if language is not forced, use game language setting from config if (!forcelang) { langtxt = GetLangSettingFromGame(id_text); strcpy(langcode, ConvertLangTextToCode(langtxt)); } /* if enabled, force English title for all games set to Japanese */ if (forcejptoen && (!strcmp(langcode, "JA"))) strcpy(langcode, "EN"); /* load title from nodes */ nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", "EN", MXML_NO_DESCEND); if (nodefound != NULL) { GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, title_text_EN, sizeof(title_text_EN)); } nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", langcode, MXML_NO_DESCEND); if (nodefound != NULL) { GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, title_text, sizeof(title_text)); } /* fall back to English title if prefered language was not found */ if (!strcmp(title_text, "")) { strcpy(title_text, title_text_EN); } snprintf(id_text, 7, "%s", id_text); title_set(id_text, title_text); } } // free memory mxmlIndexDelete(nodeindex); //if (xmldebug) xmlloadtime = dbg_time2(NULL); } void GetPublisherFromGameid(char *idtxt, char *dest, int destsize) { /* guess publisher from company list using last two characters from game id */ nodeindextmp = mxmlIndexNew(nodedata, "company", NULL); nodeidtmp = mxmlIndexReset(nodeindextmp); *element_text = 0; char publishercode[3]; sprintf(publishercode, "%c%c", idtxt[4], idtxt[5]); while (strcmp(element_text, publishercode) != 0) { nodeidtmp = mxmlIndexFind(nodeindextmp, "company", NULL); if (nodeidtmp != NULL) { strlcpy(element_text, mxmlElementGetAttr(nodeidtmp, "code"), sizeof(element_text)); } else { break; } } if (!strcmp(element_text, publishercode)) { strlcpy(dest, mxmlElementGetAttr(nodeidtmp, "name"), destsize); } else { strcpy(dest, ""); } // free memory mxmlIndexDelete(nodeindextmp); } bool LoadGameInfoFromXML(char* gameid, char* langtxt) /* gameid: full game id */ /* langtxt: "English","French","German" */ { bool exist = false; if (!xml_loaded || nodedata == NULL) return exist; // load game info using forced language, or game individual setting, or main language setting char langcode[100] = ""; if (!strcmp(langtxt, "")) langtxt = GetLangSettingFromGame(gameid); strlcpy(langcode, ConvertLangTextToCode(langtxt), sizeof(langcode)); /* reset all game info */ gameinfo = gameinfo_reset; /* index all IDs */ nodeindex = mxmlIndexNew(nodedata, "id", NULL); nodeid = mxmlIndexReset(nodeindex); *element_text = 0; /* search for game matching gameid */ while (1) { nodeid = mxmlIndexFind(nodeindex, "id", NULL); if (nodeid != NULL) { get_nodetext(nodeid, element_text, sizeof(element_text)); if (!strcmp(element_text, gameid)) { break; } } else { break; } } if (!strcmp(element_text, gameid)) { /* text from elements */ strlcpy(gameinfo.id, element_text, sizeof(gameinfo.id)); GetTextFromNode(nodeid, nodedata, "region", NULL, NULL, MXML_NO_DESCEND, gameinfo.region, sizeof(gameinfo.region)); GetTextFromNode(nodeid, nodedata, "version", NULL, NULL, MXML_NO_DESCEND, gameinfo.version, sizeof(gameinfo.version)); GetTextFromNode(nodeid, nodedata, "genre", NULL, NULL, MXML_NO_DESCEND, gameinfo.genre, sizeof(gameinfo.genre)); GetTextFromNode(nodeid, nodedata, "developer", NULL, NULL, MXML_NO_DESCEND, gameinfo.developer, sizeof(gameinfo.developer)); GetTextFromNode(nodeid, nodedata, "publisher", NULL, NULL, MXML_NO_DESCEND, gameinfo.publisher, sizeof(gameinfo.publisher)); GetPublisherFromGameid(gameid, gameinfo.publisherfromid, sizeof(gameinfo.publisherfromid)); /* text from attributes */ GetTextFromNode(nodeid, nodedata, "date", "year", NULL, MXML_NO_DESCEND, gameinfo.year, sizeof(gameinfo.year)); GetTextFromNode(nodeid, nodedata, "date", "month", NULL, MXML_NO_DESCEND, gameinfo.month, sizeof(gameinfo.month)); GetTextFromNode(nodeid, nodedata, "date", "day", NULL, MXML_NO_DESCEND, gameinfo.day, sizeof(gameinfo.day)); GetTextFromNode(nodeid, nodedata, "rating", "type", NULL, MXML_NO_DESCEND, gameinfo.ratingtype, sizeof(gameinfo.ratingtype)); GetTextFromNode(nodeid, nodedata, "rating", "value", NULL, MXML_NO_DESCEND, gameinfo.ratingvalue, sizeof(gameinfo.ratingvalue)); GetTextFromNode(nodeid, nodedata, "rom", "crc", NULL, MXML_NO_DESCEND, gameinfo.iso_crc, sizeof(gameinfo.iso_crc)); GetTextFromNode(nodeid, nodedata, "rom", "md5", NULL, MXML_NO_DESCEND, gameinfo.iso_md5, sizeof(gameinfo.iso_md5)); GetTextFromNode(nodeid, nodedata, "rom", "sha1", NULL, MXML_NO_DESCEND, gameinfo.iso_sha1, sizeof(gameinfo.iso_sha1)); /* text from child elements */ nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", "EN", MXML_NO_DESCEND); if (nodefound != NULL) { GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, gameinfo.title_EN, sizeof(gameinfo.title_EN)); GetTextFromNode(nodefound, nodedata, "synopsis", NULL, NULL, MXML_DESCEND, gameinfo.synopsis_EN, sizeof(gameinfo.synopsis_EN)); } nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", langcode, MXML_NO_DESCEND); if (nodefound != NULL) { GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, gameinfo.title, sizeof(gameinfo.title)); GetTextFromNode(nodefound, nodedata, "synopsis", NULL, NULL, MXML_DESCEND, gameinfo.synopsis, sizeof(gameinfo.synopsis)); } // fall back to English title and synopsis if prefered language was not found if (!strcmp(gameinfo.title, "")) { strlcpy(gameinfo.title, gameinfo.title_EN, sizeof(gameinfo.title)); } if (!strcmp(gameinfo.synopsis, "")) { strlcpy(gameinfo.synopsis, gameinfo.synopsis_EN, sizeof(gameinfo.synopsis)); } /* list locale lang attributes */ nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", NULL, MXML_NO_DESCEND); if (nodefound != NULL) { int incr = 0; while (nodefound != NULL) { ++incr; strlcpy(gameinfo.locales[incr], mxmlElementGetAttr(nodefound, "lang"), sizeof(gameinfo.locales[incr])); nodefound = mxmlWalkNext(nodefound, nodedata, MXML_NO_DESCEND); if (nodefound != NULL) { nodefound = mxmlFindElement(nodefound, nodedata, "locale", "lang", NULL, MXML_NO_DESCEND); } } } /* unbounded child elements */ GetTextFromNode(nodeid, nodedata, "wi-fi", "players", NULL, MXML_NO_DESCEND, gameinfo.wifiplayers, sizeof(gameinfo.wifiplayers)); nodefound = mxmlFindElement(nodeid, nodedata, "wi-fi", NULL, NULL, MXML_NO_DESCEND); if (nodefound != NULL) { gameinfo.wifiCnt = 0; nodeindextmp = mxmlIndexNew(nodefound, "feature", NULL); nodeidtmp = mxmlIndexReset(nodeindextmp); while (nodeidtmp != NULL) { nodeidtmp = mxmlIndexFind(nodeindextmp, "feature", NULL); if (nodeidtmp != NULL) { ++gameinfo.wifiCnt; GetTextFromNode(nodeidtmp, nodedata, "feature", NULL, NULL, MXML_DESCEND, gameinfo.wififeatures[gameinfo.wifiCnt], sizeof(gameinfo.wififeatures[gameinfo.wifiCnt])); gameinfo.wififeatures[gameinfo.wifiCnt][0] = toupper( (int) gameinfo.wififeatures[gameinfo.wifiCnt][0]); if (gameinfo.wifiCnt == XML_ELEMMAX) break; } } mxmlIndexDelete(nodeindextmp); // placed after each mxmlIndexNew to prevent memory leak } nodefound = mxmlFindElement(nodeid, nodedata, "rating", NULL, NULL, MXML_NO_DESCEND); if (nodefound != NULL) { gameinfo.descriptorCnt = 0; nodeindextmp = mxmlIndexNew(nodefound, "descriptor", NULL); nodeidtmp = mxmlIndexReset(nodeindextmp); while (nodeidtmp != NULL) { nodeidtmp = mxmlIndexFind(nodeindextmp, "descriptor", NULL); if (nodeidtmp != NULL) { ++gameinfo.descriptorCnt; GetTextFromNode(nodeidtmp, nodedata, "descriptor", NULL, NULL, MXML_DESCEND, gameinfo.ratingdescriptors[gameinfo.descriptorCnt], sizeof(gameinfo.ratingdescriptors[gameinfo.descriptorCnt])); if (gameinfo.descriptorCnt == XML_ELEMMAX) break; } } mxmlIndexDelete(nodeindextmp); } GetTextFromNode(nodeid, nodedata, "input", "players", NULL, MXML_NO_DESCEND, gameinfo.players, sizeof(gameinfo.players)); nodefound = mxmlFindElement(nodeid, nodedata, "input", NULL, NULL, MXML_NO_DESCEND); if (nodefound != NULL) { gameinfo.accessoryCnt = 0; gameinfo.accessoryReqCnt = 0; nodeindextmp = mxmlIndexNew(nodefound, "control", NULL); nodeidtmp = mxmlIndexReset(nodeindextmp); while (nodeidtmp != NULL) { nodeidtmp = mxmlIndexFind(nodeindextmp, "control", NULL); if (nodeidtmp != NULL) { if (!strcmp(mxmlElementGetAttr(nodeidtmp, "required"), "true") && gameinfo.accessoryReqCnt < XML_ELEMMAX) { ++gameinfo.accessoryReqCnt; strlcpy(gameinfo.accessoriesReq[gameinfo.accessoryReqCnt], mxmlElementGetAttr(nodeidtmp, "type"), sizeof(gameinfo.accessoriesReq[gameinfo.accessoryReqCnt])); } else if (gameinfo.accessoryCnt < XML_ELEMMAX) { ++gameinfo.accessoryCnt; strlcpy(gameinfo.accessories[gameinfo.accessoryCnt], mxmlElementGetAttr(nodeidtmp, "type"), sizeof(gameinfo.accessories[gameinfo.accessoryCnt])); } } } mxmlIndexDelete(nodeindextmp); } /* convert rating value */ ConvertRating(gameinfo.ratingvalue, gameinfo.ratingtype, "CERO", gameinfo.ratingvalueCERO, sizeof(gameinfo.ratingvalueCERO)); ConvertRating(gameinfo.ratingvalue, gameinfo.ratingtype, "ESRB", gameinfo.ratingvalueESRB, sizeof(gameinfo.ratingvalueESRB)); ConvertRating(gameinfo.ratingvalue, gameinfo.ratingtype, "PEGI", gameinfo.ratingvaluePEGI, sizeof(gameinfo.ratingvaluePEGI)); /* provide genre as an array: gameinfo.genresplit */ if (strcmp(gameinfo.genre, "") != 0) { gameinfo.genreCnt = 0; const char *delimgenre = ",;"; char genretxt[200]; strlcpy(genretxt, gameinfo.genre, sizeof(genretxt)); char *splitresult; splitresult = strtok(genretxt, delimgenre); if (splitresult != NULL) { ++gameinfo.genreCnt; trimcopy(splitresult, splitresult, strlen(splitresult) + 1); strlcpy(gameinfo.genresplit[gameinfo.genreCnt], splitresult, sizeof(gameinfo.genresplit[gameinfo.genreCnt])); gameinfo.genresplit[gameinfo.genreCnt][0] = toupper((int) gameinfo.genresplit[gameinfo.genreCnt][0]); while (splitresult != NULL) { splitresult = strtok(NULL, delimgenre); if (splitresult != NULL && strcmp(splitresult, "") != 0) { ++gameinfo.genreCnt; trimcopy(splitresult, splitresult, strlen(splitresult) + 1); strlcpy(gameinfo.genresplit[gameinfo.genreCnt], splitresult, sizeof(gameinfo.genresplit[gameinfo.genreCnt])); gameinfo.genresplit[gameinfo.genreCnt][0] = toupper( (int) gameinfo.genresplit[gameinfo.genreCnt][0]); if (gameinfo.genreCnt == XML_ELEMMAX) break; } } } } exist = true; } else { /*game not found */ exist = false; } // if game was not found or info is missing // guess publisher from game id in case it is missing if (!strcmp(gameinfo.publisher, "")) { GetPublisherFromGameid(gameid, gameinfo.publisherfromid, sizeof(gameinfo.publisherfromid)); strlcpy(gameinfo.publisher, gameinfo.publisherfromid, sizeof(gameinfo.publisher)); } // if missing, get region from game ID if (!strcmp(gameinfo.region, "")) { if (gameid[3] == 'E') strlcpy(gameinfo.region, "NTSC-U", sizeof(gameinfo.region)); if (gameid[3] == 'J') strlcpy(gameinfo.region, "NTSC-J", sizeof(gameinfo.region)); if (gameid[3] == 'W') strlcpy(gameinfo.region, "NTSC-J", sizeof(gameinfo.region)); if (gameid[3] == 'K') strlcpy(gameinfo.region, "NTSC-K", sizeof(gameinfo.region)); if (gameid[3] == 'P') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'D') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'F') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'I') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'S') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'H') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'U') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'X') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'Y') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); if (gameid[3] == 'Z') strlcpy(gameinfo.region, "PAL", sizeof(gameinfo.region)); } // free memory mxmlIndexDelete(nodeindex); return exist; } void PrintGameInfo(bool showfullinfo) { if (showfullinfo) { //Con_Clear(); //printf("id: %s version: %s region: %s",gameinfo.id, gameinfo.version, gameinfo.region); //printf("title: %s\n",gameinfo.title); int i; printf("languages:"); for (i = 1; strcmp(gameinfo.locales[i], "") != 0; i++) { printf(" %s", gameinfo.locales[i]); } printf("\n"); //printf("developer: %s\n",gameinfo.developer); //printf("publisher: %s\n",gameinfo.publisher); //printf("publisher from ID: %s\n",gameinfo.publisherfromid); printf("year:%s month:%s day:%s\n", gameinfo.year, gameinfo.month, gameinfo.day); printf("genre: %s\n", gameinfo.genre); //printf("rating: %s %s (CERO: %s ESRB: %s PEGI: %s)\n",gameinfo.ratingtype, gameinfo.ratingvalue, // gameinfo.ratingvalueCERO,gameinfo.ratingvalueESRB,gameinfo.ratingvaluePEGI); printf("content descriptors:"); for (i = 1; strcmp(gameinfo.wififeatures[i], "") != 0; i++) { printf(" %s", gameinfo.ratingdescriptors[i]); } printf("\n"); printf("players: %s online: %s\n", gameinfo.players, gameinfo.wifiplayers); printf("online features:"); for (i = 1; strcmp(gameinfo.wififeatures[i], "") != 0; i++) { printf(" %s", gameinfo.wififeatures[i]); } printf("\n"); printf("required accessories:"); for (i = 1; strcmp(gameinfo.accessoriesReq[i], "") != 0; i++) { printf(" %s", gameinfo.accessoriesReq[i]); } printf("\n"); printf("accessories:"); for (i = 1; strcmp(gameinfo.accessories[i], "") != 0; i++) { printf(" %s", gameinfo.accessories[i]); } printf("\n"); //printf("iso_crc: %s iso_md5: %s\n",gameinfo.iso_crc,gameinfo.iso_md5); //printf("iso_sha1: %s\n",gameinfo.iso_sha1); //printf("synopsis: %s\n",gameinfo.synopsis); } else { char linebuf[1000] = ""; if (xmldebug) { //char xmltime[100]; //sprintf(xmltime,"%d",xmlloadtime); //printf("xml load time: %s\n",xmltime); /* printf("xml forcelang: %s\n",CFG.db_lang); printf("xml url: %s\n",CFG.db_url); printf("xml file: %s\n",CFG.db_filename); char xmljptoen[100]; sprintf(xmljptoen,"%d",CFG.db_JPtoEN); printf("xml JPtoEN: %s\n",xmljptoen); */ printf(MemInfo()); // guidebug } //printf("%s: ",gameidfull); //printf("%s\n",gameinfo.title); if (strcmp(gameinfo.year, "") != 0) snprintf(linebuf, sizeof(linebuf), "%s ", gameinfo.year); if (strcmp(gameinfo.publisher, "") != 0) snprintf(linebuf, sizeof(linebuf), "%s%s", linebuf, gameinfo.publisher); if (strcmp(gameinfo.developer, "") != 0 && strcmp(gameinfo.developer, gameinfo.publisher) != 0) snprintf( linebuf, sizeof(linebuf), "%s / %s", linebuf, gameinfo.developer); if (strlen(linebuf) >= 100) { char buffer[200] = ""; strlcpy(buffer, linebuf, 100); strcat(buffer, "..."); snprintf(linebuf, sizeof(linebuf), "%s", buffer); } printf("%s\n", linebuf); strcpy(linebuf, ""); if (strcmp(gameinfo.ratingvalue, "") != 0) { snprintf(linebuf, sizeof(linebuf), "rated %s", gameinfo.ratingvalue); if (!strcmp(gameinfo.ratingtype, "PEGI")) snprintf(linebuf, sizeof(linebuf), "%s+ ", linebuf); snprintf(linebuf, sizeof(linebuf), "%s ", linebuf); } if (strcmp(gameinfo.players, "") != 0) { snprintf(linebuf, sizeof(linebuf), "%sfor %s player", linebuf, gameinfo.players); if (atoi(gameinfo.players) > 1) snprintf(linebuf, sizeof(linebuf), "%ss", linebuf); if (atoi(gameinfo.wifiplayers) > 1) snprintf(linebuf, sizeof(linebuf), "%s (%s online)", linebuf, gameinfo.wifiplayers); } printf("%s\n", linebuf); strcpy(linebuf, ""); } } char *MemInfo() { char linebuf[300] = ""; char memtotal[20]; char memused[20]; char memnotinuse[20]; char memcanbefreed[20]; struct mallinfo mymallinfo = mallinfo(); sprintf(memtotal, "%d", mymallinfo.arena / 1024); sprintf(memused, "%d", mymallinfo.uordblks / 1024); sprintf(memnotinuse, "%d", mymallinfo.fordblks / 1024); sprintf(memcanbefreed, "%d", mymallinfo.keepcost / 1024); snprintf(linebuf, sizeof(linebuf), "all:%sKB used:%sKB notused:%sKB canfree:%sKB", memtotal, memused, memnotinuse, memcanbefreed); char *minfo[300]; *minfo = linebuf; return *minfo; } /*-------------------------------------------------------------------------------------*/ /* get_nodetext() - Get the text for a node, taken from mini-mxml example mxmldoc.c */ char * get_nodetext(mxml_node_t *node, char *buffer, int buflen) /* O - Text in node, I - Node to get, I - Buffer, I - Size of buffer */ { char *ptr, *end; /* Pointer into buffer, End of buffer */ int len; /* Length of node */ mxml_node_t *current; /* Current node */ ptr = buffer; end = buffer + buflen - 1; for (current = node->child; current && ptr < end; current = current->next) { if (current->type == MXML_TEXT) { if (current->value.text.whitespace) *ptr++ = ' '; len = (int) strlen(current->value.text.string); if (len > (int) (end - ptr)) len = (int) (end - ptr); memcpy(ptr, current->value.text.string, len); ptr += len; } else if (current->type == MXML_OPAQUE) { len = (int) strlen(current->value.opaque); if (len > (int) (end - ptr)) len = (int) (end - ptr); memcpy(ptr, current->value.opaque, len); ptr += len; } } *ptr = '\0'; return (buffer); } int GetRatingForGame(char *gameid) { int retval = -1; if (!xml_loaded || nodedata == NULL) return -1; /* index all IDs */ nodeindex = mxmlIndexNew(nodedata, "id", NULL); nodeid = mxmlIndexReset(nodeindex); *element_text = 0; /* search for game matching gameid */ while (1) { nodeid = mxmlIndexFind(nodeindex, "id", NULL); if (nodeid != NULL) { get_nodetext(nodeid, element_text, sizeof(element_text)); if (!strcmp(element_text, gameid)) { break; } } else { break; } } if (!strcmp(element_text, gameid)) { char type[5], value[5], dest[5]; GetTextFromNode(nodeid, nodedata, "rating", "type", NULL, MXML_NO_DESCEND, type, sizeof(type)); GetTextFromNode(nodeid, nodedata, "rating", "value", NULL, MXML_NO_DESCEND, value, sizeof(value)); ConvertRating(value, type, "PEGI", dest, sizeof(dest)); retval = atoi(dest); } return retval; }