*Reworked the whole WiiTDB.xml parsing. This is now done with mxml due to a lack of memory the file is now streamed. Now the full wiitdb.xml file with all languages is always used. The update of WiiTDB is also changed. It is now only updated if the version of the wiitdb.xml file does not match the version of the online file.

*WiiTDB now falls back to english if the locale language is not found for Titles/Synopsis
*Some clean up and memory leak fixes in game info prompt and adjusted the info get to the new WiiTDB reading method.
*Added a few new useful functions from WiiXplorer (DownloadToFileWithProgress, ShowError,...)
*Disabled the console output after the GUI is started up. The info is only output to gecko in GUI mode now.
This commit is contained in:
dimok321 2010-12-03 18:38:57 +00:00
parent 4c07b6db74
commit 500dc4020f
25 changed files with 2730 additions and 1190 deletions

View File

@ -2,8 +2,8 @@
<app version="1">
<name> USB Loader GX</name>
<coder>USB Loader GX Team</coder>
<version>1.0 r1006</version>
<release_date>201011300400</release_date>
<version>1.0 r1007</version>
<release_date>201012031819</release_date>
<short_description>Loads games from USB-devices</short_description>
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <sys/iosupport.h>
/* init-globals */
static bool geckoinit = false;
@ -75,4 +76,46 @@ void hexdump(void *d, int len)
}
}
static ssize_t __out_write(struct _reent *r, int fd, const char *ptr, size_t len)
{
if(geckoinit && ptr)
{
u32 level;
level = IRQ_Disable();
usb_sendbuffer(1, ptr, len);
IRQ_Restore(level);
}
return len;
}
static const devoptab_t gecko_out = {
"stdout", // device name
0, // size of file structure
NULL, // device open
NULL, // device close
__out_write,// device write
NULL, // device read
NULL, // device seek
NULL, // device fstat
NULL, // device stat
NULL, // device link
NULL, // device unlink
NULL, // device chdir
NULL, // device rename
NULL, // device mkdir
0, // dirStateSize
NULL, // device diropen_r
NULL, // device dirreset_r
NULL, // device dirnext_r
NULL, // device dirclose_r
NULL // device statvfs_r
};
void USBGeckoOutput()
{
devoptab_list[STD_OUT] = &gecko_out;
devoptab_list[STD_ERR] = &gecko_out;
}
#endif /* NO_DEBUG */

View File

@ -14,6 +14,7 @@ extern "C"
void gprintf(const char *str, ...);
bool InitGecko();
void hexdump(void *d, int len);
void USBGeckoOutput();
#else
#define gprintf(...)
#define InitGecko() false

View File

@ -37,6 +37,7 @@
extern u32 infilesize;
extern u32 uncfilesize;
extern char wiiloadVersion[2];
extern int connection;
HomebrewBrowser::HomebrewBrowser()
: FlyingButtonsMenu(tr( "Homebrew Launcher" ))
@ -293,7 +294,7 @@ int HomebrewBrowser::ReceiveFile()
len = infilesize - read;
else len = NETWORKBLOCKSIZE;
int result = network_read(buffer+read, len);
int result = network_read(connection, buffer+read, len);
if (result < 0)
{
@ -310,7 +311,7 @@ int HomebrewBrowser::ReceiveFile()
}
char filename[101];
network_read((u8*) &filename, 100);
network_read(connection, (u8*) &filename, 100);
// Do we need to unzip this thing?
if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4)

View File

@ -17,7 +17,7 @@
int updateLanguageFiles()
{
char languageFiles[50][MAXLANGUAGEFILES];
DirList Dir(Settings.languagefiles_path);
//give up now if we didn't find any
@ -48,7 +48,7 @@ int updateLanguageFiles()
char codeurl[200];
snprintf(codeurl, sizeof(codeurl), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s",
languageFiles[j]);
snprintf(savepath, sizeof(savepath), "%s%s", Settings.languagefiles_path, languageFiles[j]);
snprintf(savepath, sizeof(savepath), "%s/%s", Settings.languagefiles_path, languageFiles[j]);
struct block file = downloadfile(codeurl);

View File

@ -118,6 +118,9 @@ int main(int argc, char *argv[])
return BootGame(argv[1]);
}
//! Now we startup the GUI so no need for console prints. Output only to gecko.
USBGeckoOutput();
//! Init the rest of the System
Sys_Init();
SetupPads();

View File

@ -8,7 +8,9 @@
#include "wpad.h"
#include "fatmounter.h"
#include "usbloader/wbfs.h"
#include "xml/xml.h"
#include "usbloader/GameList.h"
#include "settings/GameTitles.h"
#include "xml/WiiTDB.hpp"
extern int load_from_fs;
extern char game_partition[6];
@ -163,11 +165,8 @@ int MountGamePartition(bool ShowGUI)
}
gprintf("\tOpenXMLDatabase\n");
// open database if needed, load titles if needed
if (CheckFile(Settings.titlestxt_path))
OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride, true);
gprintf("MountGamePartition() return: %i\n", ret);
GameTitles.LoadTitlesFromWiiTDB(Settings.titlestxt_path);
return ret;
}

View File

@ -0,0 +1,280 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <ogcsys.h>
#include <stdio.h>
#include <string.h>
#include "language/gettext.h"
#include "networkops.h"
#include "http.h"
#include "FileOperations/fileops.h"
#include "prompts/PromptWindows.h"
#include "prompts/ProgressWindow.h"
#include "utils/ShowError.h"
/****************************************************************************
* Download a file from a given url with a Progressbar
****************************************************************************/
int DownloadFileToMem(const char *url, u8 **inbuffer, u32 *size)
{
if(strncasecmp(url, "http://", strlen("http://")) != 0)
{
ShowError(tr("Not a valid URL"));
return -1;
}
char *path = strchr(url + strlen("http://"), '/');
if(!path)
{
ShowError(tr("Not a valid URL path"));
return -2;
}
int domainlength = path - url - strlen("http://");
if(domainlength == 0)
{
ShowError(tr("Not a valid domain"));
return -3;
}
char domain[domainlength + 1];
strncpy(domain, url + strlen("http://"), domainlength);
domain[domainlength] = '\0';
int connection = GetConnection(domain);
if(connection < 0)
{
ShowError(tr("Could not connect to the server."));
return -4;
}
char header[1024];
char * ptr = header;
ptr += sprintf(ptr, "GET %s HTTP/1.1\r\n", path);
ptr += sprintf(ptr, "Host: %s\r\n", domain);
ptr += sprintf(ptr, "Referer: %s\r\n", domain);
ptr += sprintf(ptr, "User-Agent: USB Loader GX\r\n");
ptr += sprintf(ptr, "Pragma: no-cache\r\n");
ptr += sprintf(ptr, "Cache-Control: no-cache\r\n");
ptr += sprintf(ptr, "Connection: close\r\n\r\n");
char filename[255];
memset(filename, 0, sizeof(filename));
u32 filesize = network_request(connection, header, (char *) &filename);
if(!filesize)
{
net_close(connection);
ShowError(tr("Filesize is 0 Byte."));
return -5;
}
u32 blocksize = 10*1024;
u8 * buffer = (u8 *) malloc(filesize);
if(!buffer)
{
net_close(connection);
ShowError(tr("Not enough memory."));
return -6;
}
u32 done = 0;
while(done < filesize)
{
ShowProgress(tr("Downloading file..."), 0, filename, (f32) done, (f32) filesize, true, true);
if(blocksize > filesize - done)
blocksize = filesize - done;
s32 read = network_read(connection, buffer+done, blocksize);
if(read < 0)
{
free(buffer);
ProgressStop();
net_close(connection);
ShowError(tr("Transfer failed"));
return -8;
}
else if(!read)
break;
done += read;
}
ProgressStop();
net_close(connection);
*inbuffer = buffer;
*size = filesize;
return 1;
}
/****************************************************************************
* Download a file from a given url to a given path with a Progressbar
****************************************************************************/
int DownloadFileToPath(const char *orig_url, const char *dest, bool UseFilename)
{
if(!orig_url || !dest)
{
ShowError(tr("No URL or Path specified."));
return -2;
}
bool addhttp = false;
if(strncasecmp(orig_url, "http://", strlen("http://")) != 0)
{
addhttp = true;
}
char url[strlen(orig_url) + (addhttp ? strlen("http://") : 0) + 1];
if(addhttp)
snprintf(url, sizeof(url), "http://%s", orig_url);
else
strcpy(url, orig_url);
char *path = strchr(url + strlen("http://"), '/');
if(!path)
{
ShowError(tr("Not a valid URL path"));
return -2;
}
int domainlength = path - url - strlen("http://");
if(domainlength == 0)
{
ShowError(tr("Not a valid domain"));
return -3;
}
char domain[domainlength + 1];
strncpy(domain, url + strlen("http://"), domainlength);
domain[domainlength] = '\0';
int connection = GetConnection(domain);
if(connection < 0)
{
ShowError(tr("Could not connect to the server."));
return -4;
}
char header[1024];
char * ptr = header;
ptr += sprintf(ptr, "GET %s HTTP/1.1\r\n", path);
ptr += sprintf(ptr, "Host: %s\r\n", domain);
ptr += sprintf(ptr, "Referer: %s\r\n", domain);
ptr += sprintf(ptr, "User-Agent: WiiXplorer\r\n");
ptr += sprintf(ptr, "Pragma: no-cache\r\n");
ptr += sprintf(ptr, "Cache-Control: no-cache\r\n");
ptr += sprintf(ptr, "Connection: close\r\n\r\n");
char filename[255];
memset(filename, 0, sizeof(filename));
u32 filesize = network_request(connection, header, (char *) &filename);
if(!filesize)
{
net_close(connection);
ShowError(tr("Filesize is 0 Byte."));
return -5;
}
u32 blocksize = 10*1024;
u8 *buffer = (u8 *) malloc(blocksize);
if(!buffer)
{
net_close(connection);
ShowError(tr("Not enough memory."));
return -6;
}
if(UseFilename)
{
if(dest[strlen(dest)-1] != '/')
strcat((char *) dest, "/");
CreateSubfolder(dest);
strcat((char *) dest, filename);
}
FILE *file = fopen(dest, "wb");
if(!file)
{
net_close(connection);
free(buffer);
ShowError(tr("Cannot write to destination."));
return -7;
}
u32 done = 0;
while(done < filesize)
{
ShowProgress(tr("Downloading file..."), 0, filename, (f32) done, (f32) filesize, true, true);
if(blocksize > filesize - done)
blocksize = filesize - done;
s32 read = network_read(connection, buffer, blocksize);
if(read < 0)
{
free(buffer);
ProgressStop();
net_close(connection);
fclose(file);
ShowError(tr("Transfer failed"));
return -8;
}
else if(!read)
break;
fwrite(buffer, 1, read, file);
done += read;
}
free(buffer);
ProgressStop();
net_close(connection);
fclose(file);
return done;
}

View File

@ -0,0 +1,32 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef FILE_DOWNLOADER_H_
#define FILE_DOWNLOADER_H_
int DownloadFileToMem(const char *url, u8 **inbuffer, u32 *size);
int DownloadFileToPath(const char *url, const char *dest, bool UseFilename = true);
#endif

View File

@ -14,10 +14,12 @@
#include "prompts/PromptWindows.h"
#include "language/gettext.h"
#include "settings/CSettings.h"
#include "networkops.h"
#include "main.h"
#include "http.h"
#include "svnrev.h"
#include "buildtype.h"
#include "gecko.h"
#include "update.h"
#define PORT 4299
@ -110,7 +112,7 @@ bool ShutdownWC24()
return onlinefix;
}
s32 network_request(const char * request, char * filename)
s32 network_request(s32 connect, const char * request, char * filename)
{
char buf[1024];
char *ptr = NULL;
@ -119,7 +121,7 @@ s32 network_request(const char * request, char * filename)
s32 ret;
/* Send request */
ret = net_send(connection, request, strlen(request), 0);
ret = net_send(connect, request, strlen(request), 0);
if (ret < 0) return ret;
/* Clear buffer */
@ -127,7 +129,7 @@ s32 network_request(const char * request, char * filename)
/* Read HTTP header */
for (cnt = 0; !strstr(buf, "\r\n\r\n"); cnt++)
if (net_recv(connection, buf + cnt, 1, 0) <= 0) return -1;
if (net_recv(connect, buf + cnt, 1, 0) <= 0) return -1;
/* HTTP request OK? */
if (!strstr(buf, "HTTP/1.1 200 OK")) return -1;
@ -157,7 +159,7 @@ s32 network_request(const char * request, char * filename)
return size;
}
s32 network_read(u8 *buf, u32 len)
s32 network_read(s32 connect, u8 *buf, u32 len)
{
u32 read = 0;
s32 ret = -1;
@ -166,7 +168,7 @@ s32 network_read(u8 *buf, u32 len)
while (read < len)
{
/* Read network data */
ret = net_read(connection, buf + read, len - read);
ret = net_read(connect, buf + read, len - read);
if (ret < 0) return ret;
/* Read finished */
@ -221,11 +223,78 @@ s32 download_request(const char * url, char * filename)
char header[strlen(path) + strlen(domain) + strlen(url) + 100];
sprintf(header, "GET %s HTTP/1.1\r\nHost: %s\r\nReferer: %s\r\nConnection: close\r\n\r\n", path, domain, url);
s32 filesize = network_request(header, filename);
s32 filesize = network_request(connection, header, filename);
return filesize;
}
/****************************************************************************
* HTML HEAD request
***************************************************************************/
char * HEAD_Request(const char * url)
{
if(strncmp(url, "http://", strlen("http://")) != 0)
{
gprintf("Not a valid URL");
return NULL;
}
char *path = strchr(url + strlen("http://"), '/');
if(!path)
{
gprintf("Not a valid URL path");
return NULL;
}
int domainlength = path - url - strlen("http://");
if(domainlength == 0)
{
gprintf("Not a valid domain");
return NULL;
}
char domain[domainlength + 1];
strncpy(domain, url + strlen("http://"), domainlength);
domain[domainlength] = '\0';
connection = GetConnection(domain);
if(connection < 0)
{
gprintf("Could not connect to the server.");
return NULL;
}
char header[strlen(path)+strlen(domain)*2+150];
sprintf(header, "HEAD %s HTTP/1.1\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: USB Loader GX\r\nConnection: close\r\n\r\n", path, domain, domain);
/* Send request */
s32 ret = net_send(connection, header, strlen(header), 0);
if (ret < 0)
{
CloseConnection();
return NULL;
}
u32 cnt = 0;
char * buf = (char *) malloc(1024);
memset(buf, 0, 1024);
for (cnt = 0; !strstr(buf, "\r\n\r\n") && cnt < 1024; cnt++)
{
if(net_recv(connection, buf + cnt, 1, 0) <= 0)
{
CloseConnection();
free(buf);
return NULL;
}
}
CloseConnection();
return buf;
}
void CloseConnection()
{

View File

@ -14,12 +14,12 @@ bool IsNetworkInit(void);
char * GetNetworkIP(void);
char * GetIncommingIP(void);
bool ShutdownWC24();
s32 network_request(const char * request, char * filename);
s32 network_read(u8 *buf, u32 len);
s32 network_request(s32 connection, const char * request, char * filename);
s32 network_read(s32 connection, u8 *buf, u32 len);
s32 download_request(const char * url, char * filename = NULL);
void CloseConnection();
int CheckUpdate();
char * HEAD_Request(const char * url);
void HaltNetworkThread();
void ResumeNetworkWait();
void ResumeNetworkThread();

View File

@ -29,10 +29,19 @@
#include <stdio.h>
#include <string.h>
#include <ogcsys.h>
#include <string>
#include "gecko.h"
#include "ZipFile.h"
#include "http.h"
#include "networkops.h"
#include "HTML_Stream.h"
#include "FileDownloader.h"
#include "settings/CSettings.h"
#include "settings/GameTitles.h"
#include "xml/WiiTDB.hpp"
static const char * WiiTDB_URL = "http://wiitdb.com/wiitdb.zip";
/****************************************************************************
* Checking if an Update is available
@ -76,3 +85,72 @@ int CheckForBetaUpdate()
return revnumber;
}
static bool CheckNewWiiTDBVersion(const char *url)
{
u64 Version = 0;
char * HEAD_Responde = HEAD_Request(url);
if(!HEAD_Responde)
return false;
char * version_ptr = strstr(HEAD_Responde, "X-WiiTDB-Timestamp: ");
if(version_ptr)
{
version_ptr += strlen("X-WiiTDB-Timestamp: ");
Version = strtoull(version_ptr, NULL, 10);
}
free(HEAD_Responde);
std::string Title;
std::string Filepath = Settings.titlestxt_path;
if(Settings.titlestxt_path[Filepath.size()-1] != '/')
Filepath += '/';
Filepath += "wiitdb.xml";
WiiTDB XML_DB;
if(!XML_DB.OpenFile((Filepath.c_str())))
return true; //! If no file exists we need the file
u64 ExistingVersion = XML_DB.GetWiiTDBVersion();
gprintf("Existing WiiTDB Version: %llu Online WiiTDB Version: %llu\n", ExistingVersion, Version);
return (ExistingVersion != Version);
}
int UpdateWiiTDB()
{
if(CheckNewWiiTDBVersion(WiiTDB_URL) == false)
{
gprintf("Not updating WiiTDB: Version is the same\n");
return -1;
}
gprintf("Updating WiiTDB...\n");
string ZipPath = Settings.titlestxt_path;
if(Settings.titlestxt_path[ZipPath.size()-1] != '/')
ZipPath += '/';
ZipPath += "wiitdb.zip";
int filesize = DownloadFileToPath(WiiTDB_URL, ZipPath.c_str(), false);
if(filesize <= 0)
return -1;
ZipFile zFile(ZipPath.c_str());
bool result = zFile.ExtractAll(Settings.titlestxt_path);
//! The zip file is not needed anymore so we can remove it
remove(ZipPath.c_str());
//! Reload all titles because the file changed now.
GameTitles.LoadTitlesFromWiiTDB(Settings.titlestxt_path);
return (result ? filesize : -1);
}

View File

@ -1,34 +1,35 @@
/***************************************************************************
* Copyright (C) 2009
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* update.h
*
* Update operations
* for Wii-Xplorer 2009
***************************************************************************/
#ifndef _UPDATEOPS_H_
#define _UPDATEOPS_H_
int CheckForBetaUpdate();
#endif
/***************************************************************************
* Copyright (C) 2009
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* update.h
*
* Update operations
* for Wii-Xplorer 2009
***************************************************************************/
#ifndef _UPDATEOPS_H_
#define _UPDATEOPS_H_
int CheckForBetaUpdate();
int UpdateWiiTDB();
#endif

View File

@ -20,6 +20,7 @@
#include "settings/CGameStatistics.h"
#include "settings/GameTitles.h"
#include "network/networkops.h"
#include "network/update.h"
#include "network/http.h"
#include "prompts/PromptWindows.h"
#include "prompts/gameinfo.h"
@ -58,6 +59,7 @@ extern u8 reset;
extern u8 mountMethod;
extern struct discHdr *dvdheader;
extern char game_partition[6];
extern int connection;
/****************************************************************************
* OnScreenNumpad
@ -2663,60 +2665,6 @@ int ProgressDownloadWindow(int choice2)
}
}
/**Temporary redownloading 1st image because of a fucking corruption bug **/
#if 0 // is no longer necessary, since libfat is fixed
char URLFile[100];
struct block file = downloadfile( URLFile );
if ( choice2 == 2 )
{
while ( tries < serverCnt3d )
{
sprintf( URLFile, "%s%s", server3d, missingFiles[0] );
sprintf( imgPath, "%s%s", Settings.covers_path, missingFiles[0] );
file = downloadfile( URLFile );
if ( !( file.size == 36864 || file.size <= 1024 || file.size <= 1174 || file.size == 7386 || file.size == 4446 || file.data == NULL ) )break;
tries++;
}
}
if ( choice2 == 3 )
{
while ( tries < serverCntDisc )
{
sprintf( URLFile, "%s%s", serverDisc, missingFiles[0] );
sprintf( imgPath, "%s%s", Settings.disc_path, missingFiles[0] );
file = downloadfile( URLFile );
if ( !( file.size == 36864 || file.size <= 1024 || file.size <= 1174 || file.size == 7386 || file.size == 4446 || file.data == NULL ) )break;
tries++;
}
}
if ( choice2 == 1 )
{
while ( tries < serverCnt2d )
{
sprintf( URLFile, "%s%s", server2d, missingFiles[0] );
sprintf( imgPath, "%s%s", Settings.covers2d_path, missingFiles[0] );
file = downloadfile( URLFile );
if ( !( file.size == 36864 || file.size <= 1024 || file.size <= 1174 || file.size == 7386 || file.size == 4446 || file.data == NULL ) )break;
tries++;
}
}
if ( file.size == 36864 || file.size <= 1024 || file.size == 7386 || file.size <= 1174 || file.size == 4446 || file.data == NULL )
{
}
else
{
if ( file.data != NULL )
{
// save png to sd card
FILE *pfile;
pfile = fopen( imgPath, "wb" );
fwrite( file.data, 1, file.size, pfile );
fclose ( pfile );
free( file.data );
}
}
#endif
HaltGui();
mainWindow->Remove(&promptWindow);
mainWindow->SetState(STATE_DEFAULT);
@ -2886,12 +2834,6 @@ int ProgressUpdateWindow()
}
}
//make the URL to get XML based on our games
//std::string allocates the memory and does not depend on stack
std::string XMLurl;
XMLurl.resize(4096);
build_XML_URL(&XMLurl[0], XMLurl.size());
char dolpath[150];
// char dolpathsuccess[150];//use coverspath as a folder for the update wad so we dont make a new folder and have to delete it
snprintf( dolpath, sizeof( dolpath ), "%sULNR.wad", Settings.covers_path );
@ -2937,33 +2879,7 @@ int ProgressUpdateWindow()
titleTxt.SetTextf( "%s USB Loader GX", tr( "Updating" ) );
msgTxt.SetPosition( 0, 100 );
msgTxt.SetTextf( "%s", tr( "Updating WiiTDB.zip" ) );
char wiitdbpath[200];
char wiitdbpathtmp[200];
struct block file = downloadfile( XMLurl.c_str() );
if ( file.data != NULL )
{
snprintf( wiitdbpath, sizeof( wiitdbpath ), "%swiitdb_%s.zip", Settings.titlestxt_path, game_partition );
snprintf( wiitdbpathtmp, sizeof( wiitdbpathtmp ), "%swiitmp_%s.zip", Settings.titlestxt_path, game_partition );
rename( wiitdbpath, wiitdbpathtmp );
pfile = fopen( wiitdbpath, "wb" );
fwrite( file.data, 1, file.size, pfile );
fclose( pfile );
free( file.data );
CloseXMLDatabase();
if ( OpenXMLDatabase( Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride == 1 ? true : false, true ) ) // open file, reload titles, keep in memory
{
remove( wiitdbpathtmp );
}
else
{
remove( wiitdbpath );
rename( wiitdbpathtmp, wiitdbpath );
OpenXMLDatabase( Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride == 1 ? true : false, true ); // open file, reload titles, keep in memory
}
}
UpdateWiiTDB();
msgTxt.SetTextf( "%s", tr( "Updating Language Files:" ) );
updateLanguageFiles();
promptWindow.Append( &progressbarEmptyImg );
@ -3271,8 +3187,7 @@ int ProgressUpdateWindow()
if (IsNetworkInit() && ret >= 0)
{
updatemode = WindowPrompt(tr( "What do you want to update?" ), 0, "USB Loader GX", tr( "WiiTDB Files" ),
tr( "Language File" ), tr( "Cancel" ));
updatemode = WindowPrompt(tr( "What do you want to update?" ), 0, "USB Loader GX", tr( "WiiTDB Files" ), tr( "Language File" ), tr( "Cancel" ));
mainWindow->SetState(STATE_DISABLED);
promptWindow.SetState(STATE_DEFAULT);
mainWindow->ChangeFocus(&promptWindow);
@ -3344,7 +3259,7 @@ int ProgressUpdateWindow()
blksize = (u32) (filesize - i);
if (blksize > BLOCKSIZE) blksize = BLOCKSIZE;
ret = network_read(blockbuffer, blksize);
ret = network_read(connection, blockbuffer, blksize);
if (ret != (s32) blksize)
{
failed = -1;
@ -3390,36 +3305,7 @@ int ProgressUpdateWindow()
free(file.data);
}
msgTxt.SetTextf("%s", tr( "Updating WiiTDB.zip" ));
char wiitdbpath[200];
char wiitdbpathtmp[200];
file = downloadfile(XMLurl.c_str());
if (file.data != NULL)
{
CreateSubfolder(Settings.titlestxt_path);
snprintf(wiitdbpath, sizeof(wiitdbpath), "%swiitdb_%s.zip",
Settings.titlestxt_path, game_partition);
snprintf(wiitdbpathtmp, sizeof(wiitdbpathtmp), "%swiitmp_%s.zip",
Settings.titlestxt_path, game_partition);
rename(wiitdbpath, wiitdbpathtmp);
pfile = fopen(wiitdbpath, "wb");
fwrite(file.data, 1, file.size, pfile);
fclose(pfile);
free(file.data);
CloseXMLDatabase();
if (OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language,
Settings.db_JPtoEN, true, Settings.titlesOverride == 1 ? true : false, true)) // open file, reload titles, keep in memory
{
remove(wiitdbpathtmp);
}
else
{
remove(wiitdbpath);
rename(wiitdbpathtmp, wiitdbpath);
OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language,
Settings.db_JPtoEN, true, Settings.titlesOverride == 1 ? true : false,
true); // open file, reload titles, keep in memory
}
}
UpdateWiiTDB();
msgTxt.SetTextf("%s", tr( "Updating Language Files:" ));
updateLanguageFiles();
}
@ -3445,33 +3331,10 @@ int ProgressUpdateWindow()
else if (updatemode == 2)
{
msgTxt.SetTextf("%s", tr( "Updating WiiTDB.zip" ));
char wiitdbpath[200];
char wiitdbpathtmp[200];
struct block file = downloadfile(XMLurl.c_str());
if (file.data != NULL)
if(UpdateWiiTDB() < 0)
{
CreateSubfolder(Settings.titlestxt_path);
snprintf(wiitdbpath, sizeof(wiitdbpath), "%swiitdb_%s.zip", Settings.titlestxt_path, game_partition);
snprintf(wiitdbpathtmp, sizeof(wiitdbpathtmp), "%swiitmp_%s.zip", Settings.titlestxt_path,
game_partition);
rename(wiitdbpath, wiitdbpathtmp);
FILE *pfile = fopen(wiitdbpath, "wb");
fwrite(file.data, 1, file.size, pfile);
fclose(pfile);
free(file.data);
CloseXMLDatabase();
if (OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true,
Settings.titlesOverride == 1 ? true : false, true)) // open file, reload titles, keep in memory
{
remove(wiitdbpathtmp);
}
else
{
remove(wiitdbpath);
rename(wiitdbpathtmp, wiitdbpath);
OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true,
Settings.titlesOverride == 1 ? true : false, true); // open file, reload titles, keep in memory
}
msgTxt.SetTextf("%s", tr( "WiiTDB is up to date." ));
sleep(3);
}
ret = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
#include <string.h>
#include "GameTitles.h"
#include "CSettings.h"
#include "usbloader/GameList.h"
#include "xml/WiiTDB.hpp"
CGameTitles GameTitles;
@ -64,3 +67,28 @@ void CGameTitles::SetDefault()
//! Free vector memory
std::vector<GameTitle>().swap(TitleList);
}
void CGameTitles::LoadTitlesFromWiiTDB(const char * path)
{
this->SetDefault();
if(!path || !Settings.titlesOverride)
return;
gameList.LoadUnfiltered();
std::string Title;
std::string Filepath = path;
if(path[strlen(path)-1] != '/')
Filepath += '/';
Filepath += "wiitdb.xml";
WiiTDB XML_DB(Filepath.c_str());
XML_DB.SetLanguageCode(Settings.db_language);
for(int i = 0; i < gameList.GameCount(); ++i)
{
if(XML_DB.GetTitle((const char *) gameList[i]->id, Title))
this->SetGameTitle(gameList[i]->id, Title.c_str());
}
}

View File

@ -28,6 +28,8 @@ class CGameTitles
//! Overload
const char * GetTitle(const struct discHdr *header);
//! Load Game Titles from WiiTDB
void LoadTitlesFromWiiTDB(const char * path);
//! Set default game titles
void SetDefault();
protected:

View File

@ -123,13 +123,7 @@ GuiSettingsMenu::GuiSettingsMenu()
GuiSettingsMenu::~GuiSettingsMenu()
{
if (Settings.titlesOverride != OldTitlesOverride)
{
CloseXMLDatabase();
GameTitles.SetDefault();
if(Settings.titlesOverride)
OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride, true);
}
GameTitles.LoadTitlesFromWiiTDB(Settings.titlestxt_path);
}
void GuiSettingsMenu::SetOptionValues()

View File

@ -131,17 +131,17 @@ GameLoadSM::GameLoadSM()
GameLoadSM::~GameLoadSM()
{
// if partition has changed, Reinitialize it
//! if partition has changed, Reinitialize it
if (Settings.partition != OldSettingsPartition)
{
PartInfo pinfo = partitions.pinfo[Settings.partition];
partitionEntry pentry = partitions.pentry[Settings.partition];
WBFS_OpenPart(pinfo.part_fs, pinfo.index, pentry.sector, pentry.size, (char *) &game_partition);
load_from_fs = pinfo.part_fs;
CloseXMLDatabase();
GameTitles.SetDefault();
OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride, true);
//! Reload the new game titles
gameList.ReadGameList();
GameTitles.LoadTitlesFromWiiTDB(Settings.titlestxt_path);
}
}

View File

@ -28,6 +28,7 @@
/*** Extern variables ***/
extern u8 shutdown;
extern u8 reset;
extern int connection;
int DownloadTheme(const char *url, const char *title)
{
@ -72,7 +73,7 @@ int DownloadTheme(const char *url, const char *title)
ShowProgress(tr( "Downloading file" ), 0, (char*) filename, done, filesize, true);
int ret = network_read(buffer, blocksize);
int ret = network_read(connection, buffer, blocksize);
if (ret < 0)
{
free(buffer);

View File

@ -0,0 +1,21 @@
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "language/gettext.h"
#include "prompts/PromptWindows.h"
extern "C" void ShowError(const char * format, ...)
{
char *tmp=0;
va_list va;
va_start(va, format);
if((vasprintf(&tmp, format, va)>=0) && tmp)
{
WindowPrompt(tr("Error:"), tmp, tr("OK"));
}
va_end(va);
if(tmp)
free(tmp);
}

14
source/utils/ShowError.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SHOWERROR_H_
#define SHOWERROR_H_
#ifdef __cplusplus
extern "C" {
#endif
void ShowError(const char * format, ...);
#ifdef __cplusplus
}
#endif
#endif

998
source/xml/WiiTDB.cpp Normal file
View File

@ -0,0 +1,998 @@
/****************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include "WiiTDB.hpp"
#define NAME_OFFSET_DB "wiitdb_offsets.bin"
#define MAXREADSIZE 1024*1024 // Cache size only for parsing the offsets: 1MB
typedef struct _ReplaceStruct
{
const char * orig;
char replace;
short size;
} ReplaceStruct;
//! More replacements can be added if needed
static const ReplaceStruct Replacements[] =
{
{ "&gt;", '>', 4 },
{ "&lt;", '<', 4 },
{ "&quot;", '\"', 6 },
{ "&apos;", '\'', 6 },
{ "&amp;", '&', 5 },
{ NULL, '\0', 0 }
};
WiiTDB::WiiTDB()
: file(0), LangCode("EN"), GameNodeCache(0)
{
}
WiiTDB::WiiTDB(const char * filepath)
: file(0), LangCode("EN"), GameNodeCache(0)
{
OpenFile(filepath);
}
WiiTDB::~WiiTDB()
{
CloseFile();
}
bool WiiTDB::OpenFile(const char * filepath)
{
if(!filepath)
return false;
file = fopen(filepath, "rb");
if(file)
{
int pos;
string OffsetsPath = filepath;
if((pos = OffsetsPath.find_last_of('/')) != (int) string::npos)
OffsetsPath[pos] = '\0';
else
OffsetsPath.clear(); //! Relative path
LoadGameOffsets(OffsetsPath.c_str());
}
return (file != NULL);
}
void WiiTDB::CloseFile()
{
OffsetMap.clear();
vector<GameOffsets>().swap(OffsetMap);
if(GameNodeCache)
delete [] GameNodeCache;
GameNodeCache = NULL;
if(file)
fclose(file);
file = NULL;
}
bool WiiTDB::LoadGameOffsets(const char * path)
{
if(!path)
return false;
string OffsetDBPath = path;
if(strlen(path) > 0 && path[strlen(path)-1] != '/')
OffsetDBPath += '/';
OffsetDBPath += NAME_OFFSET_DB;
FILE * fp = fopen(OffsetDBPath.c_str(), "rb");
if(!fp)
{
bool result = ParseFile();
if(result)
SaveGameOffsets(OffsetDBPath.c_str());
return result;
}
unsigned long long ExistingVersion = GetWiiTDBVersion();
unsigned long long Version = 0;
unsigned int NodeCount = 0;
fread(&Version, 1, sizeof(Version), fp);
if(ExistingVersion != Version)
{
fclose(fp);
bool result = ParseFile();
if(result)
SaveGameOffsets(OffsetDBPath.c_str());
return result;
}
fread(&NodeCount, 1, sizeof(NodeCount), fp);
if(NodeCount == 0)
{
fclose(fp);
bool result = ParseFile();
if(result)
SaveGameOffsets(OffsetDBPath.c_str());
return result;
}
OffsetMap.resize(NodeCount);
if(fread(&OffsetMap[0], 1, NodeCount*sizeof(GameOffsets), fp) != NodeCount*sizeof(GameOffsets))
{
fclose(fp);
bool result = ParseFile();
if(result)
SaveGameOffsets(OffsetDBPath.c_str());
return result;
}
fclose(fp);
return true;
}
bool WiiTDB::SaveGameOffsets(const char * path)
{
if(OffsetMap.size() == 0 || !path)
return false;
FILE * fp = fopen(path, "wb");
if(!fp)
return false;
unsigned long long ExistingVersion = GetWiiTDBVersion();
unsigned int NodeCount = OffsetMap.size();
if(fwrite(&ExistingVersion, 1, sizeof(ExistingVersion), fp) < 0)
{
fclose(fp);
return false;
}
if(fwrite(&NodeCount, 1, sizeof(NodeCount), fp) < 0)
{
fclose(fp);
return false;
}
if(fwrite(&OffsetMap[0], 1, NodeCount*sizeof(GameOffsets), fp) < 0)
{
fclose(fp);
return false;
}
fclose(fp);
return true;
}
unsigned long long WiiTDB::GetWiiTDBVersion()
{
if(!file)
return 0;
char TmpText[1024];
if(GetData(TmpText, 0, sizeof(TmpText)) < 0)
return 0;
char * VersionText = GetNodeText(TmpText, "<WiiTDB version=\"", "/>");
if(!VersionText)
return 0;
return strtoull(VersionText, NULL, 10);
}
size_t WiiTDB::GetData(char * data, int offset, int size)
{
if(!file || !data)
return -1;
fseek(file, offset, SEEK_SET);
return fread(data, 1, size, file);
}
char * WiiTDB::LoadGameNode(const char * id)
{
unsigned int read = 0;
GameOffsets * offset = this->GetGameOffset(id);
if(!offset)
return NULL;
char * data = new (std::nothrow) char[offset->nodesize+1];
if(!data)
return NULL;
if((read = GetData(data, offset->gamenode, offset->nodesize)) != offset->nodesize)
{
delete [] data;
return NULL;
}
data[read] = '\0';
return data;
}
char * WiiTDB::GetGameNode(const char * id)
{
char * data = NULL;
if(GameNodeCache != 0 && strncmp(id, GameIDCache, strlen(GameIDCache)) == 0)
{
data = new (std::nothrow) char[strlen(GameNodeCache)+1];
if(data)
strcpy(data, GameNodeCache);
}
else
{
if(GameNodeCache)
delete [] GameNodeCache;
GameNodeCache = LoadGameNode(id);
if(GameNodeCache)
{
snprintf(GameIDCache, sizeof(GameIDCache), id);
data = new (std::nothrow) char[strlen(GameNodeCache)+1];
if(data)
strcpy(data, GameNodeCache);
}
}
return data;
}
GameOffsets * WiiTDB::GetGameOffset(const char * gameID)
{
for(unsigned int i = 0; i < OffsetMap.size(); ++i)
{
if(strncmp(gameID, OffsetMap[i].gameID, strlen(OffsetMap[i].gameID)) == 0)
return &OffsetMap[i];
}
return 0;
}
static inline char * CleanText(char * in_text)
{
if(!in_text)
return NULL;
const char * ptr = in_text;
char * text = in_text;
while(*ptr != '\0')
{
for(int i = 0; Replacements[i].orig != 0; ++i)
{
if(strncmp(ptr, Replacements[i].orig, Replacements[i].size) == 0)
{
ptr += Replacements[i].size;
*text = Replacements[i].replace;
++text;
i = 0;
continue;
}
}
if(*ptr == '\r')
{
++ptr;
continue;
}
*text = *ptr;
++ptr;
++text;
}
*text = '\0';
return in_text;
}
char * WiiTDB::GetNodeText(char * data, const char * nodestart, const char * nodeend)
{
if(!data || !nodestart || !nodeend)
return NULL;
char * position = strstr(data, nodestart);
if(!position)
return NULL;
position += strlen(nodestart);
char * end = strstr(position, nodeend);
if(!end)
return NULL;
*end = '\0';
return CleanText(position);
}
char * WiiTDB::SeekLang(char * text, const char * langcode)
{
if(!text || !langcode) return NULL;
char * ptr = text;
while((ptr = strstr(ptr, "<locale lang=")) != NULL)
{
ptr += strlen("<locale lang=\"");
if(strncmp(ptr, langcode, strlen(langcode)) == 0)
{
//! Cut off all the other languages
char * end = strstr(ptr, "</locale>");
if(!end)
return NULL;
end += strlen("</locale>");
*end = '\0';
return ptr;
}
}
return NULL;
}
bool WiiTDB::ParseFile()
{
OffsetMap.clear();
if(!file)
return false;
char * Line = new (std::nothrow) char[MAXREADSIZE+1];
if(!Line)
return false;
bool readnew = false;
int i, currentPos = 0;
int read = 0;
const char * gameNode = NULL;
const char * idNode = NULL;
const char * gameEndNode = NULL;
while((read = GetData(Line, currentPos, MAXREADSIZE)) > 0)
{
gameNode = Line;
readnew = false;
//! Ensure the null termination at the end
Line[read] = '\0';
while((gameNode = strstr(gameNode, "<game name=\"")) != NULL)
{
idNode = strstr(gameNode, "<id>");
gameEndNode = strstr(gameNode, "</game>");
if(!idNode || !gameEndNode)
{
//! We are in the middle of the game node, reread complete node and more
currentPos += (gameNode-Line);
fseek(file, currentPos, SEEK_SET);
readnew = true;
break;
}
idNode += strlen("<id>");
gameEndNode += strlen("</game>");
int size = OffsetMap.size();
OffsetMap.resize(size+1);
for(i = 0; i < 7 && *idNode != '<'; ++i, ++idNode)
OffsetMap[size].gameID[i] = *idNode;
OffsetMap[size].gameID[i] = '\0';
OffsetMap[size].gamenode = currentPos+(gameNode-Line);
OffsetMap[size].nodesize = (gameEndNode-gameNode);
gameNode = gameEndNode;
}
if(readnew)
continue;
currentPos += read;
}
delete [] Line;
return true;
}
bool WiiTDB::GetTitle(const char * id, string & title)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * language = SeekLang(data, LangCode.c_str());
if(!language)
{
language = SeekLang(data, "EN");
if(!language)
{
delete [] data;
return false;
}
}
char * the_title = GetNodeText(language, "<title>", "</title>");
if(!the_title)
{
delete [] data;
return false;
}
title = the_title;
delete [] data;
return true;
}
bool WiiTDB::GetSynopsis(const char * id, string & synopsis)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * language = SeekLang(data, LangCode.c_str());
if(!language)
{
language = SeekLang(data, "EN");
if(!language)
{
delete [] data;
return false;
}
}
char * the_synopsis = GetNodeText(language, "<synopsis>", "</synopsis>");
if(!the_synopsis)
{
delete [] data;
return false;
}
synopsis = the_synopsis;
delete [] data;
return true;
}
bool WiiTDB::GetRegion(const char * id, string & region)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * the_region = GetNodeText(data, "<region>", "</region>");
if(!the_region)
{
delete [] data;
return false;
}
region = the_region;
delete [] data;
return true;
}
bool WiiTDB::GetDeveloper(const char * id, string & dev)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * the_dev = GetNodeText(data, "<developer>", "</developer>");
if(!the_dev)
{
delete [] data;
return false;
}
dev = the_dev;
delete [] data;
return true;
}
bool WiiTDB::GetPublisher(const char * id, string & pub)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * the_pub = GetNodeText(data, "<publisher>", "</publisher>");
if(!the_pub)
{
delete [] data;
return false;
}
pub = the_pub;
delete [] data;
return true;
}
unsigned int WiiTDB::GetPublishDate(const char * id)
{
if(!id)
return 0;
char * data = GetGameNode(id);
if(!data)
return 0;
char * year_string = GetNodeText(data, "<date year=\"", "/>");
if(!year_string)
{
delete [] data;
return 0;
}
unsigned int year, day, month;
year = atoi(year_string);
char * month_string = strstr(year_string, "month=\"");
if(!month_string)
{
delete [] data;
return 0;
}
month_string += strlen("month=\"");
month = atoi(month_string);
char * day_string = strstr(month_string, "day=\"");
if(!day_string)
{
delete [] data;
return 0;
}
day_string += strlen("day=\"");
day = atoi(day_string);
delete [] data;
return ((year & 0xFFFF) << 16 | (month & 0xFF) << 8 | (day & 0xFF));
}
bool WiiTDB::GetGenreList(const char * id, vector<string> & genre)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * the_genre = GetNodeText(data, "<genre>", "</genre>");
if(!the_genre)
{
delete [] data;
return false;
}
unsigned int genre_num = 0;
const char * ptr = the_genre;
while(*ptr != '\0')
{
if(genre_num >= genre.size())
genre.resize(genre_num+1);
if(*ptr == ',' || *ptr == '/' || *ptr == ';')
{
ptr++;
while(*ptr == ' ') ptr++;
genre[genre_num].push_back('\0');
genre_num++;
continue;
}
if(genre[genre_num].size() == 0)
genre[genre_num].push_back(toupper((int)*ptr));
else
genre[genre_num].push_back(*ptr);
++ptr;
}
genre[genre_num].push_back('\0');
delete [] data;
return true;
}
const char * WiiTDB::RatingToString(int rating)
{
switch(rating)
{
case 0:
return "CERO";
case 1:
return "ESRB";
case 2:
return "PEGI";
default:
break;
}
return NULL;
}
int WiiTDB::GetRating(const char * id)
{
int rating = -1;
if(!id)
return rating;
char * data = GetGameNode(id);
if(!data)
return rating;
char * rating_text = GetNodeText(data, "<rating type=\"", "/>");
if(!rating_text)
{
delete [] data;
return rating;
}
if(strncmp(rating_text, "CERO", 4) == 0)
rating = 0;
else if(strncmp(rating_text, "ESRB", 4) == 0)
rating = 1;
else if(strncmp(rating_text, "PEGI", 4) == 0)
rating = 2;
delete [] data;
return rating;
}
bool WiiTDB::GetRatingValue(const char * id, string & rating_value)
{
if(!id)
return false;
char * data = GetGameNode(id);
if(!data)
return false;
char * rating_text = GetNodeText(data, "<rating type=\"", "/>");
if(!rating_text)
{
delete [] data;
return false;
}
char * value_text = GetNodeText(rating_text, "value=\"", "\"");
if(!value_text)
{
delete [] data;
return false;
}
rating_value = value_text;
delete [] data;
return true;
}
int WiiTDB::GetRatingDescriptorList(const char * id, vector<string> & desc_list)
{
if(!id)
return -1;
char * data = GetGameNode(id);
if(!data)
return -1;
char * descriptor_text = GetNodeText(data, "<descriptor>", "</rating>");
if(!descriptor_text)
{
delete [] data;
return -1;
}
unsigned int list_num = 0;
desc_list.clear();
while(*descriptor_text != '\0')
{
if(strncmp(descriptor_text, "</descriptor>", strlen("</descriptor>")) == 0)
{
desc_list[list_num].push_back('\0');
descriptor_text = strstr(descriptor_text, "<descriptor>");
if(!descriptor_text)
break;
descriptor_text += strlen("<descriptor>");
list_num++;
}
if(list_num >= desc_list.size())
desc_list.resize(list_num+1);
desc_list[list_num].push_back(*descriptor_text);
++descriptor_text;
}
delete [] data;
return desc_list.size();
}
int WiiTDB::GetWifiPlayers(const char * id)
{
int players = -1;
if(!id)
return players;
char * data = GetGameNode(id);
if(!data)
return players;
char * PlayersNode = GetNodeText(data, "<wi-fi players=\"", "\">");
if(!PlayersNode)
{
delete [] data;
return players;
}
players = atoi(PlayersNode);
return players;
}
int WiiTDB::GetWifiFeatureList(const char * id, vector<string> & feat_list)
{
if(!id)
return -1;
char * data = GetGameNode(id);
if(!data)
return -1;
char * feature_text = GetNodeText(data, "<feature>", "</wi-fi>");
if(!feature_text)
{
delete [] data;
return -1;
}
unsigned int list_num = 0;
feat_list.clear();
while(*feature_text != '\0')
{
if(strncmp(feature_text, "</feature>", strlen("</feature>")) == 0)
{
feat_list[list_num].push_back('\0');
feature_text = strstr(feature_text, "<feature>");
if(!feature_text)
break;
feature_text += strlen("<feature>");
list_num++;
}
if(list_num >= feat_list.size())
feat_list.resize(list_num+1);
if(feat_list[list_num].size() == 0)
feat_list[list_num].push_back(toupper((int)*feature_text));
else
feat_list[list_num].push_back(*feature_text);
++feature_text;
}
delete [] data;
return feat_list.size();
}
int WiiTDB::GetPlayers(const char * id)
{
int players = -1;
if(!id)
return players;
char * data = GetGameNode(id);
if(!data)
return players;
char * PlayersNode = GetNodeText(data, "<input players=\"", "\">");
if(!PlayersNode)
{
delete [] data;
return players;
}
players = atoi(PlayersNode);
return players;
}
int WiiTDB::GetAccessoirList(const char * id, vector<Accessoir> & acc_list)
{
if(!id)
return -1;
char * data = GetGameNode(id);
if(!data)
return -1;
char * ControlsNode = GetNodeText(data, "<control type=\"", "</input>");
if(!ControlsNode)
{
delete [] data;
return -1;
}
unsigned int list_num = 0;
acc_list.clear();
while(ControlsNode && *ControlsNode != '\0')
{
if(list_num >= acc_list.size())
acc_list.resize(list_num+1);
for(const char * ptr = ControlsNode; *ptr != '"' && *ptr != '\0'; ptr++)
{
acc_list[list_num].Name.push_back(*ptr);
}
acc_list[list_num].Name.push_back('\0');
char * requiredField = strstr(ControlsNode, "required=\"");
if(!requiredField)
{
delete [] data;
return -1;
}
requiredField += strlen("required=\"");
if(strncmp(requiredField, "true", 4) == 0)
{
acc_list[list_num].Required = true;
}
else
{
acc_list[list_num].Required = false;
}
ControlsNode = strstr(requiredField, "<control type=\"");
if(ControlsNode)
ControlsNode += strlen("<control type=\"");
list_num++;
}
delete [] data;
return acc_list.size();
}
int WiiTDB::GetCaseColor(const char * id)
{
int color = -1;
if(!id)
return color;
char * data = GetGameNode(id);
if(!data)
return color;
char * ColorNode = GetNodeText(data, "<case color=\"", "\"/>");
if(!ColorNode)
{
delete [] data;
return color;
}
color = strtoul(ColorNode, NULL, 16);
return color;
}
bool WiiTDB::GetGameXMLInfo(const char * id, GameXMLInfo * gameInfo)
{
if(!id || !gameInfo)
return false;
for(int i = 0; i < 6 && id[i] != 0; ++i)
gameInfo->GameID.push_back(id[i]);
gameInfo->GameID.push_back('\0');
GetTitle(id, gameInfo->Title);
GetSynopsis(id, gameInfo->Synopsis);
GetRegion(id, gameInfo->Region);
GetDeveloper(id, gameInfo->Developer);
GetPublisher(id, gameInfo->Publisher);
gameInfo->PublishDate = GetPublishDate(id);
GetGenreList(id, gameInfo->GenreList);
gameInfo->RatingType = GetRating(id);
GetRatingValue(id, gameInfo->RatingValue);
GetRatingDescriptorList(id, gameInfo->RatingDescriptorList);
gameInfo->WifiPlayers = GetWifiPlayers(id);
GetWifiFeatureList(id, gameInfo->WifiFeatureList);
gameInfo->Players = GetPlayers(id);
GetAccessoirList(id, gameInfo->AccessoirList);
gameInfo->CaseColor = GetCaseColor(id);
return true;
}

150
source/xml/WiiTDB.hpp Normal file
View File

@ -0,0 +1,150 @@
/****************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#ifndef WIITDB_HPP_
#define WIITDB_HPP_
#include <vector>
#include <string>
using namespace std;
typedef struct _Accessoir
{
string Name;
bool Required;
} Accessoir;
typedef struct _GameXMLInfo
{
string GameID;
string Region;
string Title;
string Synopsis;
string Developer;
string Publisher;
unsigned int PublishDate;
vector<string> GenreList;
int RatingType;
string RatingValue;
vector<string> RatingDescriptorList;
int WifiPlayers;
vector<string> WifiFeatureList;
int Players;
vector<Accessoir> AccessoirList;
long CaseColor;
} GameXMLInfo;
typedef struct _GameOffsets
{
char gameID[7];
unsigned int gamenode;
unsigned int nodesize;
} __attribute__((__packed__)) GameOffsets;
class WiiTDB
{
public:
//! Constructor
WiiTDB();
//! Constructor
//! If filepath is passed the xml file is opened and the node offsets are loaded
WiiTDB(const char * filepath);
//! Destructor
~WiiTDB();
//! If filepath is passed the xml file is opened and the node offsets are loaded
bool OpenFile(const char * filepath);
//! Closes the WiiTDB xml file
void CloseFile();
//! Set the language code which should be use to find the appropriate language
//! If the language code is not found, the language code defaults to EN
void SetLanguageCode(const char * code) { if(code) LangCode = code; };
//! Get the current set language code
const char * GetLanguageCode() { return LangCode.c_str(); };
//! Get the title of a specific game id in the language defined in LangCode
bool GetTitle(const char * id, string & title);
//! Get the synopsis of a specific game id in the language defined in LangCode
bool GetSynopsis(const char * id, string & synopsis);
//! Get the region of a game for a specific game id
bool GetRegion(const char * id, string & region);
//! Get the developer of a game for a specific game id
bool GetDeveloper(const char * id, string & dev);
//! Get the publisher of a game for a specific game id
bool GetPublisher(const char * id, string & pub);
//! Get the publish date of a game for a specific game id
//! First 1 byte is the day, than 1 byte month and last 2 bytes is the year
//! year = (return >> 16), month = (return >> 8) & 0xFF, day = return & 0xFF
unsigned int GetPublishDate(const char * id);
//! Get the genre list of a game for a specific game id
bool GetGenreList(const char * id, vector<string> & genre);
//! Get the rating type for a specific game id
//! The rating type can be converted to a string with WiiTDB::RatingToString(rating)
int GetRating(const char * id);
//! Get the rating value for a specific game id
bool GetRatingValue(const char * id, string & rating_value);
//! Get the rating descriptor list inside a vector for a specific game id
//! Returns the amount of descriptors found or -1 if failed
int GetRatingDescriptorList(const char * id, vector<string> & desc_list);
//! Get the wifi player count for a specific game id
//! Returns the amount of wifi players or -1 if failed
int GetWifiPlayers(const char * id);
//! Get the wifi feature list inside a vector for a specific game id
//! Returns the amount of wifi features found or -1 if failed
int GetWifiFeatureList(const char * id, vector<string> & feat_list);
//! Get the player count for a specific game id
//! Returns the amount of players or -1 if failed
int GetPlayers(const char * id);
//! Returns the amount of accessoirs found or -1 if failed
//! Get the accessoir (inputs) list inside a vector for a specific game id
int GetAccessoirList(const char * id, vector<Accessoir> & acc_list);
//! Get the box (case) color for a specific game id
//! Returns the color in RGB (first 3 bytes)
int GetCaseColor(const char * id);
//! Get the complete game info in the GameXMLInfo struct
bool GetGameXMLInfo(const char * id, GameXMLInfo * gameInfo);
//! Convert a specific game rating to a string
static const char * RatingToString(int rating);
//! Get the version of the wiitdb xml database
unsigned long long GetWiiTDBVersion();
//! Get the entry count in the xml database
inline size_t GetEntryCount() { return OffsetMap.size(); };
private:
bool ParseFile();
bool LoadGameOffsets(const char * path);
bool SaveGameOffsets(const char * path);
inline size_t GetData(char * data, int offset, int size);
inline char * LoadGameNode(const char * id);
inline char * GetGameNode(const char * id);
inline GameOffsets * GetGameOffset(const char * id);
inline char * SeekLang(char * text, const char * langcode);
inline char * GetNodeText(char * data, const char * nodestart, const char * nodeend);
vector<GameOffsets> OffsetMap;
FILE * file;
string LangCode;
char * GameNodeCache;
char GameIDCache[7];
};
#endif