usbloadergx/source/xml/xml.cpp

452 lines
14 KiB
C++
Raw Normal View History

/*
2010-09-24 02:48:03 +02:00
Load game information from XML - Lustar
- Mini-XML by Michael Sweet
- MiniZip adapted by Tantric
2010-09-24 02:48:03 +02:00
*/
#include <malloc.h>
#include <zip/unzip.h>
#include "settings/CSettings.h"
#include "settings/CGameSettings.h"
#include "settings/GameTitles.h"
#include "xml/xml.h"
extern char game_partition[6];
/* config */
static char xmlcfg_filename[100] = "wiitdb";
static int xmlmaxsize = 1572864;
2010-09-24 02:48:03 +02:00
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;
2010-09-24 02:48:03 +02:00
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 */
2010-09-24 02:48:03 +02:00
bool OpenXMLDatabase(char* xmlfilepath, char* argdblang, bool argJPtoEN, bool openfile, bool loadtitles, bool keepopen)
{
2010-09-24 02:48:03 +02:00
if (!xml_loaded)
{
bool opensuccess = false;
char pathname[200];
2010-09-24 02:48:03 +02:00
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)
{
2010-09-24 02:48:03 +02:00
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);
}
2010-09-24 02:48:03 +02:00
if (!opensuccess && openfile)
{
CloseXMLDatabase();
return false;
}
2010-09-24 02:48:03 +02:00
if (loadtitles) LoadTitlesFromXML(argdblang, argJPtoEN);
if (!keepopen) CloseXMLDatabase();
}
else
{
2010-09-24 02:48:03 +02:00
if (loadtitles) LoadTitlesFromXML(argdblang, argJPtoEN);
if (!keepopen) CloseXMLDatabase();
}
return true;
}
void CloseXMLDatabase()
{
/* free memory */
2010-09-24 02:48:03 +02:00
if (xml_loaded)
{
2010-09-24 02:48:03 +02:00
mxmlDelete(nodedata);
mxmlDelete(nodetree);
xml_loaded = false;
}
}
2010-09-24 02:48:03 +02:00
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;
2010-09-24 02:48:03 +02:00
nodefound = mxmlFindElement(currentnode, topnode, nodename, attributename, value, descend);
if (nodefound != NULL)
{
2010-09-24 02:48:03 +02:00
if (attributename != NULL)
{
2010-09-24 02:48:03 +02:00
strlcpy(dest, mxmlElementGetAttr(nodefound, attributename), destsize);
}
else
{
2010-09-24 02:48:03 +02:00
get_nodetext(nodefound, element_text, sizeof(element_text));
strlcpy(dest, element_text, destsize);
}
}
else
{
2010-09-24 02:48:03 +02:00
strcpy(dest, "");
}
}
2010-09-24 02:48:03 +02:00
bool OpenXMLFile(char *filename)
{
//if (xmldebug) dbg_time1();
2010-09-24 02:48:03 +02:00
if (xml_loaded) return false;
nodedata = NULL;
nodetree = NULL;
nodeid = NULL;
nodeidtmp = NULL;
nodefound = NULL;
2010-09-24 02:48:03 +02:00
char* strresult = strstr(filename, ".zip");
if (strresult == NULL)
{
/* Load XML file */
FILE *filexml;
2010-09-24 02:48:03 +02:00
filexml = fopen(filename, "rb");
if (!filexml) return false;
2010-09-24 02:48:03 +02:00
nodetree = mxmlLoadFile(NULL, filexml, MXML_OPAQUE_CALLBACK);
fclose(filexml);
}
else
{
/* load zipped XML file */
2010-09-24 02:48:03 +02:00
unzFile unzfile = unzOpen(filename);
if (unzfile == NULL) return false;
unzOpenCurrentFile(unzfile);
unz_file_info zipfileinfo;
2010-09-24 02:48:03 +02:00
unzGetCurrentFileInfo(unzfile, &zipfileinfo, NULL, 0, NULL, 0, NULL, 0);
int zipfilebuffersize = zipfileinfo.uncompressed_size;
2010-09-24 02:48:03 +02:00
if (zipfilebuffersize >= xmlmaxsize)
{
2010-09-24 02:48:03 +02:00
unzCloseCurrentFile(unzfile);
unzClose(unzfile);
return false;
}
2010-09-24 02:48:03 +02:00
char * zipfilebuffer = (char *) malloc(zipfilebuffersize);
memset(zipfilebuffer, 0, zipfilebuffersize);
if (zipfilebuffer == NULL)
{
2010-09-24 02:48:03 +02:00
unzCloseCurrentFile(unzfile);
unzClose(unzfile);
return false;
}
2010-09-24 02:48:03 +02:00
unzReadCurrentFile(unzfile, zipfilebuffer, zipfilebuffersize);
unzCloseCurrentFile(unzfile);
unzClose(unzfile);
2010-09-24 02:48:03 +02:00
nodetree = mxmlLoadString(NULL, zipfilebuffer, MXML_OPAQUE_CALLBACK);
free(zipfilebuffer);
}
2010-09-24 02:48:03 +02:00
if (nodetree == NULL) return false;
2010-09-24 02:48:03 +02:00
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;
}
}
2010-09-24 02:48:03 +02:00
char *GetLangSettingFromGame(char *gameid)
{
int langcode;
GameCFG *game_cfg = GameSettings.GetGameCFG((u8*) gameid);
2010-09-24 02:48:03 +02:00
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) */
2010-09-24 02:48:03 +02:00
const char *ConvertLangTextToCode(char *languagetxt)
{
// do not convert if languagetext seems to be a language code (can be 2 or 4 letters)
2010-09-24 02:48:03 +02:00
if (strlen(languagetxt) <= 4) return languagetxt;
int i;
2010-09-24 02:48:03 +02:00
for (i = 0; i <= 10; i++)
{
2010-09-24 02:48:03 +02:00
if (!strcasecmp(languagetxt, langlist[i])) // case insensitive comparison
return langcodes[i];
}
return "";
}
2010-09-24 02:48:03 +02:00
char ConvertRatingToIndex(char *ratingtext)
{
int type = -1;
2010-09-24 02:48:03 +02:00
if (!strcmp(ratingtext, "CERO"))
{
type = 0;
}
2010-09-24 02:48:03 +02:00
if (!strcmp(ratingtext, "ESRB"))
{
type = 1;
}
2010-09-24 02:48:03 +02:00
if (!strcmp(ratingtext, "PEGI"))
{
type = 2;
}
return type;
}
int ConvertRating(const char *ratingvalue, const char *fromrating, const char *torating)
{
2010-09-24 02:48:03 +02:00
if (!strcmp(fromrating, torating))
{
int ret = atoi(ratingvalue);
if(ret < 7)
return 0;
else if(ret < 12)
return 1;
else if(ret < 16)
return 2;
else if(ret < 18)
return 3;
else
return 4;
}
int type = -1;
int desttype = -1;
type = ConvertRatingToIndex((char *) fromrating);
2010-09-24 02:48:03 +02:00
desttype = ConvertRatingToIndex((char *) torating);
if (type == -1 || desttype == -1) return -1;
/* 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;
2010-09-24 02:48:03 +02:00
for (i = 0; i <= 11; i++)
{
2010-09-24 02:48:03 +02:00
if (!strcmp(ratingtable[i][type], ratingvalue))
{
int ret = atoi(ratingtable[i][desttype]);
if(ret < 7)
return 0;
else if(ret < 12)
return 1;
else if(ret < 16)
return 2;
else if(ret < 18)
return 3;
else
return 4;
}
}
return -1;
}
2010-09-24 02:48:03 +02:00
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 */
{
2010-09-24 02:48:03 +02:00
if (nodedata == NULL) return;
bool forcelang = false;
2010-09-24 02:48:03 +02:00
if (strcmp(langtxt, "")) forcelang = true;
char langcode[10] = "";
2010-09-24 02:48:03 +02:00
if (forcelang) strcpy(langcode, ConvertLangTextToCode(langtxt)); /* convert language text into ISO 639 two-letter language code */
/* create index of <id> elements */
2010-09-24 02:48:03 +02:00
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 */
2010-09-24 02:48:03 +02:00
while (nodeid != NULL)
{
2010-09-24 02:48:03 +02:00
nodeid = mxmlIndexFind(nodeindex, "id", NULL);
if (nodeid != NULL)
{
2010-09-24 02:48:03 +02:00
strcpy(title_text, "");
strcpy(title_text_EN, "");
2010-09-24 02:48:03 +02:00
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
2010-09-24 02:48:03 +02:00
if (!forcelang)
{
2010-09-24 02:48:03 +02:00
langtxt = GetLangSettingFromGame(id_text);
strcpy(langcode, ConvertLangTextToCode(langtxt));
}
/* if enabled, force English title for all games set to Japanese */
if (forcejptoen && (strcmp(langcode, "JA")) == 0) strcpy(langcode, "EN");
/* load title from nodes */
2010-09-24 02:48:03 +02:00
nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", "EN", MXML_NO_DESCEND);
if (nodefound != NULL)
{
2010-09-24 02:48:03 +02:00
GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, title_text_EN,
sizeof(title_text_EN));
}
2010-09-24 02:48:03 +02:00
nodefound = mxmlFindElement(nodeid, nodedata, "locale", "lang", langcode, MXML_NO_DESCEND);
if (nodefound != NULL)
{
2010-09-24 02:48:03 +02:00
GetTextFromNode(nodefound, nodedata, "title", NULL, NULL, MXML_DESCEND, title_text, sizeof(title_text));
}
/* fall back to English title if prefered language was not found */
2010-09-24 02:48:03 +02:00
if (!strcmp(title_text, ""))
{
2010-09-24 02:48:03 +02:00
strcpy(title_text, title_text_EN);
}
2010-09-24 02:48:03 +02:00
snprintf(id_text, 7, "%s", id_text);
GameTitles.SetGameTitle(id_text, title_text);
}
}
// free memory
2010-09-24 02:48:03 +02:00
mxmlIndexDelete(nodeindex);
//if (xmldebug) xmlloadtime = dbg_time2(NULL);
}
2010-09-24 02:48:03 +02:00
void GetPublisherFromGameid(char *idtxt, char *dest, int destsize)
{
/* guess publisher from company list using last two characters from game id */
2010-09-24 02:48:03 +02:00
nodeindextmp = mxmlIndexNew(nodedata, "company", NULL);
nodeidtmp = mxmlIndexReset(nodeindextmp);
*element_text = 0;
char publishercode[3];
2010-09-24 02:48:03 +02:00
sprintf(publishercode, "%c%c", idtxt[4], idtxt[5]);
2010-09-24 02:48:03 +02:00
while (strcmp(element_text, publishercode) != 0)
{
2010-09-24 02:48:03 +02:00
nodeidtmp = mxmlIndexFind(nodeindextmp, "company", NULL);
if (nodeidtmp != NULL)
{
2010-09-24 02:48:03 +02:00
strlcpy(element_text, mxmlElementGetAttr(nodeidtmp, "code"), sizeof(element_text));
}
else
{
break;
}
}
2010-09-24 02:48:03 +02:00
if (!strcmp(element_text, publishercode))
{
2010-09-24 02:48:03 +02:00
strlcpy(dest, mxmlElementGetAttr(nodeidtmp, "name"), destsize);
}
else
{
2010-09-24 02:48:03 +02:00
strcpy(dest, "");
}
// free memory
2010-09-24 02:48:03 +02:00
mxmlIndexDelete(nodeindextmp);
}
char *MemInfo()
{
char linebuf[300] = "";
char memtotal[20];
char memused[20];
char memnotinuse[20];
char memcanbefreed[20];
struct mallinfo mymallinfo = mallinfo();
2010-09-24 02:48:03 +02:00
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 */
2010-09-24 02:48:03 +02:00
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 */
{
2010-09-24 02:48:03 +02:00
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;
2010-09-24 02:48:03 +02:00
for (current = node->child; current && ptr < end; current = current->next)
{
2010-09-24 02:48:03 +02:00
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;
}
2010-09-24 02:48:03 +02:00
else if (current->type == MXML_OPAQUE)
{
2010-09-24 02:48:03 +02:00
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';
2010-09-24 02:48:03 +02:00
return (buffer);
}