mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-18 09:19:17 +01:00
f3ef9104b1
*Moved all related global settings to a settings class. one for themes and individual games will follow. Probably broke some settings or theme loading, we can deal with that later and fix when someone discovers bugs.
892 lines
32 KiB
C++
892 lines
32 KiB
C++
/*
|
|
Load game information from XML - Lustar
|
|
- Mini-XML by Michael Sweet
|
|
- MiniZip adapted by Tantric
|
|
*/
|
|
|
|
#include <malloc.h>
|
|
#include "unzip/unzip.h"
|
|
#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 <id> 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;
|
|
}
|