*Completely rewrote the asynchron GuiImageData class (problems from switch Carousel<->Grid layour should be fixed now)

*Fixed bug mounting a wbfs partition which was formatted from an ext partition
*Rewrote the parental control feature. Removed loading pin or settings from the Wii Settings. Parental control is now completely managed in the loader from the settings selected and the password set.
*Saving password in config file is now encrypted
*Added loop to wait for usb when reloading the cIOS before game start


The parental control feature is filtering games like following when usb loader is locked:
level 0 (everyone 0+)		> shows only games with lvl 0
level 1 (childs 7+)		> shows games with lvl 0, 1
level 2 (teens 12+)		> shows games with lvl 0, 1, 2
level 3 (mature 16+)		> shows games with lvl 0, 1, 2, 3
level 4 (adults only 18+)	> shows all games (lvl 0, 1, 2, 3, 4)

level 4 is default when creating new configs
This commit is contained in:
dimok321 2010-12-19 18:20:33 +00:00
parent 3f03d92295
commit 2adc6cc995
30 changed files with 518 additions and 895 deletions

View File

@ -2,8 +2,8 @@
<app version="1">
<name> USB Loader GX</name>
<coder>USB Loader GX Team</coder>
<version>1.0 r1010</version>
<release_date>201012051910</release_date>
<version>1.0 r1015</version>
<release_date>201012181321</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

@ -125,7 +125,7 @@ void DirList::AddEntrie(const char * folderpath, const char * filename, u64 file
FileInfo.resize(pos+1);
FileInfo[pos].FilePath = new (std::nothrow) char[strlen(folderpath)+strlen(filename)+1];
FileInfo[pos].FilePath = new (std::nothrow) char[strlen(folderpath)+strlen(filename)+2];
if(FileInfo[pos].FilePath)
sprintf(FileInfo[pos].FilePath, "%s/%s", folderpath, filename);
FileInfo[pos].FileSize = filesize;

View File

@ -0,0 +1,65 @@
#include "libwiigui/gui.h"
#include "usbloader/disc.h"
#include "FileOperations/fileops.h"
#include "settings/CSettings.h"
#include "themes/CTheme.h"
/****************************************************************************
* LoadCoverImage
***************************************************************************/
GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D, bool noCover)
{
if (!header) return NULL;
GuiImageData *Cover = NULL;
char ID3[4];
char IDfull[7];
char Path[255];
bool flag = Prefere3D;
snprintf(ID3, sizeof(ID3), "%s", (char *) header->id);
snprintf(IDfull, sizeof(IDfull), "%s", (char *) header->id);
for (int i = 0; i < 2; ++i)
{
char *coverPath = flag ? Settings.covers_path : Settings.covers2d_path;
flag = !flag;
//Load full id image
snprintf(Path, sizeof(Path), "%s%s.png", coverPath, IDfull);
if(!CheckFile(Path))
{
snprintf(Path, sizeof(Path), "%s%s.png", coverPath, ID3);
if(!CheckFile(Path))
continue;
}
delete Cover;
Cover = new (std::nothrow) GuiImageData(Path);
//Load short id image
if (!Cover || !Cover->GetImage())
{
snprintf(Path, sizeof(Path), "%s%s.png", coverPath, ID3);
delete Cover;
Cover = new (std::nothrow) GuiImageData(Path);
}
if (Cover && Cover->GetImage()) break;
}
//Load no image
if (noCover && (!Cover || !Cover->GetImage()))
{
flag = Prefere3D;
for (int i = 0; i < 2; ++i)
{
flag = !flag;
delete Cover;
Cover = Resources::GetImageData(flag ? "nocover.png" : "nocoverFlat.png");
if (Cover && Cover->GetImage()) break;
}
}
if (Cover && !Cover->GetImage())
{
delete Cover;
Cover = NULL;
}
return Cover;
}

View File

@ -0,0 +1,6 @@
#ifndef LOADCOVERIMAGE_H_
#define LOADCOVERIMAGE_H_
GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D = true, bool noCover = true);
#endif

View File

@ -7,17 +7,18 @@
***************************************************************************/
#include "gui.h"
#include "../wpad.h"
#include "../menu.h"
#include "wpad.h"
#include "menu.h"
#include <unistd.h>
#include "gui_image_async.h"
#include "gui_gamecarousel.h"
#include "usbloader/GameList.h"
#include "settings/GameTitles.h"
#include "../settings/CSettings.h"
#include "settings/CSettings.h"
#include "libwiigui/LoadCoverImage.h"
#include "themes/CTheme.h"
#include "../main.h"
#include "main.h"
#include <string.h>
#include <math.h>
@ -108,8 +109,8 @@ GuiGameCarousel::GuiGameCarousel(int w, int h, const char *themePath, const u8 *
gamename->SetMaxWidth(280, DOTTED);
gameIndex = new int[pagesize];
game = new GuiButton *[pagesize];
coverImg = new GuiImageAsync *[pagesize];
game.resize(pagesize);
coverImg.resize(pagesize);
for (int i = 0; i < pagesize; i++)
{
@ -163,14 +164,14 @@ GuiGameCarousel::~GuiGameCarousel()
delete trigMinus;
delete gamename;
for (int i = 0; i < pagesize; i++)
{
GuiImageAsync::ClearQueue();
for (u32 i = 0; i < game.size(); ++i)
delete coverImg[i];
for (u32 i = 0; i < game.size(); ++i)
delete game[i];
}
delete[] gameIndex;
delete[] coverImg;
delete[] game;
}

View File

@ -1,8 +1,9 @@
#ifndef _GUIGAMECAROUSEL_H_
#define _GUIGAMECAROUSEL_H_
#include <vector>
#include "gui.h"
#include "../usbloader/disc.h"
#include "usbloader/disc.h"
class GuiImageAsync;
class GuiGameCarousel: public GuiElement
{
@ -29,8 +30,8 @@ class GuiGameCarousel: public GuiElement
int clickedItem;
int * gameIndex;
GuiButton ** game;
GuiImageAsync ** coverImg;
std::vector<GuiButton *> game;
std::vector<GuiImageAsync *> coverImg;
GuiText * gamename;

View File

@ -7,18 +7,19 @@
***************************************************************************/
#include "gui.h"
#include "../wpad.h"
#include "wpad.h"
#include <unistd.h>
#include "gui_gamegrid.h"
#include "gui_image_async.h"
#include "libwiigui/LoadCoverImage.h"
#include "usbloader/GameList.h"
#include "settings/GameTitles.h"
#include "../settings/CSettings.h"
#include "settings/CSettings.h"
#include "themes/CTheme.h"
#include "../prompts/PromptWindows.h"
#include "../language/gettext.h"
#include "../menu.h"
#include "prompts/PromptWindows.h"
#include "language/gettext.h"
#include "menu.h"
#include "fatmounter.h"
#include <string.h>
@ -206,23 +207,10 @@ GuiGameGrid::GuiGameGrid(int w, int h, const char *themePath, const u8 *imagebg,
{
width = w;
height = h;
// gameCnt = count; will be set later in Reload
// gameList = l; will be set later in Reload
// listOffset = 0; will be set later in Reload
// goLeft = 0; will be set later in Reload
// goRight = 0; will be set later in Reload
selectable = true;
focus = 1; // allow focus
// selectedItem = -1; will be set later in Reload
// clickedItem = -1; will be set later in Reload
/* will be set later in Reload
rows = Settings.gridRows;
if ((count<45)&&(rows==3))rows=2;
if ((count<18)&&(rows==2))rows=1;
pagesize = ROWS2PAGESIZE(rows);
*/
trigA = new GuiTrigger;
trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
trigL = new GuiTrigger;
@ -274,10 +262,6 @@ GuiGameGrid::GuiGameGrid(int w, int h, const char *themePath, const u8 *imagebg,
// Page-Stuff
gameIndex = NULL;
titleTT = NULL;
// cover = NULL;
coverImg = NULL;
game = NULL;
Reload(Settings.gridRows, 0);
}
@ -301,17 +285,22 @@ GuiGameGrid::~GuiGameGrid()
delete trig1;
delete trig2;
for (int i = pagesize - 1; i >= 0; i--)
{
delete game[i];
delete coverImg[i];
delete titleTT[i];
}
GuiImageAsync::ClearQueue();
delete[] gameIndex;
delete[] game;
delete[] coverImg;
delete[] titleTT;
for (u32 i = 0; i < game.size(); ++i)
delete game[i];
for (u32 i = 0; i < coverImg.size(); ++i)
delete coverImg[i];
for (u32 i = 0; i < titleTT.size(); ++i)
delete titleTT[i];
if(gameIndex)
delete [] gameIndex;
game.clear();
coverImg.clear();
titleTT.clear();
}
void GuiGameGrid::SetFocus(int f)
@ -447,7 +436,6 @@ void GuiGameGrid::Draw()
*/
void GuiGameGrid::ChangeRows(int n)
{
LOCK( this );
if (n != rows) Reload(n, -1);
}
@ -489,10 +477,7 @@ void GuiGameGrid::Update(GuiTrigger * t)
if (btnLeft->GetState() == STATE_CLICKED)
{
WPAD_ScanPads();
u16 buttons = 0;
for (int i = 0; i < 4; i++)
buttons |= WPAD_ButtonsHeld(i);
u32 buttons = t->wpad.btns_h;
if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_MINUS) || t->Left()))
{
btnLeft->ResetState();
@ -505,10 +490,7 @@ void GuiGameGrid::Update(GuiTrigger * t)
}
else if (btnRight->GetState() == STATE_CLICKED)
{
WPAD_ScanPads();
u16 buttons = 0;
for (int i = 0; i < 4; i++)
buttons |= WPAD_ButtonsHeld(i);
u32 buttons = t->wpad.btns_h;
if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_PLUS) || t->Right()))
{
btnRight->ResetState();
@ -721,25 +703,24 @@ void GuiGameGrid::Reload(int Rows, int ListOffset)
{
LOCK( this );
//Prevent to wait before all images are loaded before we can delete them
GuiImageAsync::ClearQueue();
// CleanUp
if (game) for (int i = pagesize - 1; i >= 0; i--)
for (u32 i = 0; i < game.size(); ++i)
delete game[i];
if (coverImg) for (int i = pagesize - 1; i >= 0; i--)
for (u32 i = 0; i < coverImg.size(); ++i)
delete coverImg[i];
// if(cover)
// for(int i=pagesize-1; i>=0; i--)
// delete cover[i];
if (titleTT) for (int i = pagesize - 1; i >= 0; i--)
for (u32 i = 0; i < titleTT.size(); ++i)
delete titleTT[i];
delete[] gameIndex;
delete[] game;
delete[] coverImg;
// delete [] cover;
delete[] titleTT;
if(gameIndex)
delete [] gameIndex;
game.clear();
coverImg.clear();
titleTT.clear();
goLeft = 0;
goRight = 0;
@ -759,10 +740,9 @@ void GuiGameGrid::Reload(int Rows, int ListOffset)
// Page-Stuff
gameIndex = new int[pagesize];
titleTT = new GuiTooltip *[pagesize];
// cover = new GuiImageData *[pagesize];
coverImg = new GuiImageAsync *[pagesize];
game = new GuiButton *[pagesize];
titleTT.resize(pagesize);
coverImg.resize(pagesize);
game.resize(pagesize);
int wsi = Settings.widescreen ? 0 : 1;
int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 );
@ -799,8 +779,7 @@ void GuiGameGrid::Reload(int Rows, int ListOffset)
coverImg[i] = NULL;
if (gameIndex[i] != -1)
{
coverImg[i] = new GuiImageAsync(GameGridLoadCoverImage, gameList[gameIndex[i]], sizeof(struct discHdr),
&noCover);
coverImg[i] = new GuiImageAsync(GameGridLoadCoverImage, gameList[gameIndex[i]], sizeof(struct discHdr), &noCover);
if (coverImg[i])
{
coverImg[i]->SetWidescreen(Settings.widescreen);

View File

@ -1,8 +1,10 @@
#ifndef _GUIGAMEGRID_H_
#define _GUIGAMEGRID_H_
#include <vector>
#include "gui.h"
#include "../usbloader/disc.h"
#include "usbloader/disc.h"
class GuiImageAsync;
class GuiGameGrid: public GuiElement
{
@ -30,9 +32,9 @@ class GuiGameGrid: public GuiElement
int goRight;
int * gameIndex;
GuiButton ** game;
GuiTooltip ** titleTT;
GuiImageAsync ** coverImg;
std::vector<GuiButton *> game;
std::vector<GuiTooltip *> titleTT;
std::vector<GuiImageAsync *> coverImg;
GuiButton * btnRight;
GuiButton * btnLeft;

View File

@ -1,187 +1,149 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
* USB Loader GX
*
* gui_imagea_sync.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
//#include <string.h>
#include <unistd.h>
#include "gui_image_async.h"
static mutex_t debugLock = LWP_MUTEX_NULL;
void debug(int Line, const char* Format, ...)
std::vector<GuiImageAsync *> GuiImageAsync::List;
lwp_t GuiImageAsync::Thread = LWP_THREAD_NULL;
mutex_t GuiImageAsync::ListLock = LWP_THREAD_NULL;
GuiImageAsync * GuiImageAsync::InUse = NULL;
u32 GuiImageAsync::ThreadCount = 0;
bool GuiImageAsync::ThreadSleep = true;
bool GuiImageAsync::CloseThread = false;
static inline void * memdup(const void* src, size_t len)
{
if (debugLock == 0) LWP_MutexInit(&debugLock, false);
if(!src) return NULL;
LWP_MutexLock(debugLock);
FILE *fp = fopen("SD:/debug.txt", "a");
if (fp)
{
char theTime[10];
time_t rawtime = time(0); //this fixes code dump caused by the clock
struct tm * timeinfo = localtime(&rawtime);
strftime(theTime, sizeof(theTime), "%H:%M:%S", timeinfo);
char format[10 + strlen(Format) + strlen(theTime)];
sprintf(format, "%s %i - %s\n", theTime, Line, Format);
va_list va;
va_start( va, Format );
vfprintf(fp, format, va);
va_end( va );
fclose(fp);
}
LWP_MutexUnlock(debugLock);
}
//#define DEBUG(format, ...) debug(__LINE__, format, ##__VA_ARGS__)
#define DEBUG(format, ...)
static void *memdup(const void* src, size_t len)
{
void *dst = malloc(len);
if (dst) memcpy(dst, src, len);
return dst;
}
static std::vector<GuiImageAsync *> List;
static u32 ThreadCount = 0;
static lwp_t Thread = LWP_THREAD_NULL;
static mutex_t ListLock = LWP_MUTEX_NULL;
static mutex_t InUseLock = LWP_MUTEX_NULL;
static GuiImageAsync *InUse = NULL;
static bool Quit = false;
static bool CanSleep = true;
void *GuiImageAsyncThread(void *arg)
static GuiImageData * StdImageLoaderCallback(void *arg)
{
while (!Quit)
{
LWP_MutexLock(ListLock);
if (List.size())
{
LWP_MutexLock(InUseLock);
InUse = List.front();
List.erase(List.begin());
LWP_MutexUnlock(ListLock);
if (InUse)
{
GuiImageData *data = InUse->callback(InUse->arg);
InUse->loadet_imgdata = data;
if (InUse->loadet_imgdata && InUse->loadet_imgdata->GetImage())
{
// InUse->SetImage(InUse->loadet_imgdata); cant use here. There can occur a deadlock
// Sets the image directly without lock. This is not fine, but it prevents a deadlock
InUse->image = InUse->loadet_imgdata->GetImage();
InUse->width = InUse->loadet_imgdata->GetWidth();
InUse->height = InUse->loadet_imgdata->GetHeight();
}
}
InUse = NULL;
LWP_MutexUnlock(InUseLock);
}
else
{
LWP_MutexUnlock(ListLock);
if (!Quit && CanSleep) LWP_SuspendThread(Thread);
}
CanSleep = true;
}
Quit = false;
return NULL;
return new GuiImageData((char *) arg);
}
static u32 GuiImageAsyncThreadInit()
GuiImageAsync::GuiImageAsync(const char *Filename, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), imgData(NULL), callback(StdImageLoaderCallback), arg(strdup(Filename))
{
if (0 == ThreadCount++)
{
CanSleep = false;
LWP_MutexInit(&ListLock, false);
LWP_MutexInit(&InUseLock, false);
LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 16384, 75);
// while(!CanSleep)
// usleep(20);
}
return ThreadCount;
}
static u32 GuiImageAsyncThreadExit()
{
if (--ThreadCount == 0)
{
Quit = true;
LWP_ResumeThread(Thread);
// while(Quit)
// usleep(20);
LWP_JoinThread(Thread, NULL);
LWP_MutexDestroy(ListLock);
LWP_MutexDestroy(InUseLock);
Thread = LWP_THREAD_NULL;
ListLock = LWP_MUTEX_NULL;
InUseLock = LWP_MUTEX_NULL;
}
return ThreadCount;
ThreadInit();
ThreadAddImage(this);
}
static void GuiImageAsyncThread_AddImage(GuiImageAsync* Image)
GuiImageAsync::GuiImageAsync(ImageLoaderCallback Callback, const void * Arg, int ArgLen, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), imgData(NULL), callback(Callback), arg(memdup(Arg, ArgLen))
{
ThreadInit();
ThreadAddImage(this);
}
GuiImageAsync::~GuiImageAsync()
{
ThreadRemoveImage(this);
ThreadExit();
while(InUse == this) usleep(100);
if (imgData) delete imgData;
if (arg) free(arg);
}
void GuiImageAsync::ThreadAddImage(GuiImageAsync *Image)
{
LWP_MutexLock(ListLock);
List.push_back(Image);
LWP_MutexUnlock(ListLock);
CanSleep = false;
// if(LWP_ThreadIsSuspended(Thread))
ThreadSleep = false;
LWP_ResumeThread(Thread);
}
static void GuiImageAsyncThread_RemoveImage(GuiImageAsync* Image)
void GuiImageAsync::ThreadRemoveImage(GuiImageAsync *Image)
{
LWP_MutexLock(ListLock);
for (std::vector<GuiImageAsync *>::iterator iter = List.begin(); iter != List.end(); iter++)
for(u32 i = 0; i < List.size(); ++i)
{
if (*iter == Image)
if(List[i] == Image)
{
List.erase(iter);
LWP_MutexLock(ListLock);
List.erase(List.begin()+i);
LWP_MutexUnlock(ListLock);
return;
break;
}
}
if (InUse == Image)
{
LWP_MutexLock(InUseLock);
LWP_MutexUnlock(InUseLock);
}
}
void GuiImageAsync::ClearQueue()
{
LWP_MutexLock(ListLock);
List.clear();
LWP_MutexUnlock(ListLock);
}
/**
* Constructor for the GuiImageAsync class.
*/
GuiImageData *StdImageLoaderCallback(void *arg)
void * GuiImageAsync::GuiImageAsyncThread(void *arg)
{
return new GuiImageData((char*) arg);
while(!CloseThread)
{
if(ThreadSleep)
LWP_SuspendThread(Thread);
while(!List.empty() && !CloseThread)
{
LWP_MutexLock(ListLock);
InUse = List.front();
List.erase(List.begin());
LWP_MutexUnlock(ListLock);
if (!InUse)
continue;
InUse->imgData = InUse->callback(InUse->arg);
if (InUse->imgData && InUse->imgData->GetImage())
{
InUse->width = InUse->imgData->GetWidth();
InUse->height = InUse->imgData->GetHeight();
InUse->image = InUse->imgData->GetImage();
}
InUse = NULL;
}
ThreadSleep = true;
}
return NULL;
}
GuiImageAsync::GuiImageAsync(const char *Filename, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), loadet_imgdata(NULL), callback(StdImageLoaderCallback), arg(strdup(Filename))
u32 GuiImageAsync::ThreadInit()
{
GuiImageAsyncThreadInit();
GuiImageAsyncThread_AddImage(this);
}
GuiImageAsync::GuiImageAsync(ImageLoaderCallback Callback, void *Arg, int ArgLen, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), loadet_imgdata(NULL), callback(Callback), arg(memdup(Arg, ArgLen))
{
DEBUG( "Constructor %p", this );
GuiImageAsyncThreadInit();
GuiImageAsyncThread_AddImage(this);
}
GuiImageAsync::~GuiImageAsync()
{
GuiImageAsyncThread_RemoveImage(this);
GuiImageAsyncThreadExit();
DEBUG( "Deconstructor %p (loadet_imgdata=%p)", this, loadet_imgdata );
if (loadet_imgdata) delete loadet_imgdata;
if (arg) free(arg);
if (Thread == LWP_THREAD_NULL)
{
LWP_MutexInit(&ListLock, false);
LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 32768, 80);
}
return ++ThreadCount;
}
u32 GuiImageAsync::ThreadExit()
{
//! We don't need to always shutdown and startup the thread, especially
//! since this is a nested startup/shutdown from the gui thread.
//! It's fine with being put to suspended only.
/*
if (--ThreadCount == 0)
{
CloseThread = true;
LWP_ResumeThread(Thread);
LWP_JoinThread(Thread, NULL);
LWP_MutexUnlock(ListLock);
LWP_MutexDestroy(ListLock);
Thread = LWP_THREAD_NULL;
ListLock = LWP_MUTEX_NULL;
ListLock = LWP_MUTEX_NULL;
}
*/
return --ThreadCount;
}

View File

@ -1,25 +1,37 @@
#ifndef _GUIIMAGEASYNC_H_
#define _GUIIMAGEASYNC_H_
#// arg is a pointer created with malloc()
// when the image is destroied then will also the arg deleted with free()
#include <vector>
#include "libwiigui/gui.h"
typedef GuiImageData * (*ImageLoaderCallback)(void *arg);
class GuiImageAsync: public GuiImage
{
public:
GuiImageAsync(const char *Filename, GuiImageData * PreloadImg);
GuiImageAsync(ImageLoaderCallback Callback, void *arg, int arglen, GuiImageData * PreloadImg);
GuiImageAsync(ImageLoaderCallback Callback, const void *Arg, int ArgLen, GuiImageData * PreloadImg);
~GuiImageAsync();
static void ClearQueue();
private:
GuiImageData *loadet_imgdata;
friend void loader(GuiImageAsync *InUse);
friend void Setter(GuiImageAsync *InUse);
friend void *GuiImageAsyncThread(void *arg);
GuiImageData *imgData;
ImageLoaderCallback callback;
void *arg;
static void * GuiImageAsyncThread(void *arg);
static void ThreadAddImage(GuiImageAsync* Image);
static void ThreadRemoveImage(GuiImageAsync* Image);
static u32 ThreadInit();
static u32 ThreadExit();
static std::vector<GuiImageAsync *> List;
static lwp_t Thread;
static mutex_t ListLock;
static GuiImageAsync * InUse;
static u32 ThreadCount;
static bool ThreadSleep;
static bool CloseThread;
};
#endif /*_GUIIMAGEASYNC_H_*/

View File

@ -196,58 +196,6 @@ void ExitGUIThreads()
}
}
/****************************************************************************
* LoadCoverImage
***************************************************************************/
GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D, bool noCover)
{
if (!header) return NULL;
GuiImageData *Cover = NULL;
char ID[4];
char IDfull[7];
char Path[100];
bool flag = Prefere3D;
snprintf(ID, sizeof(ID), "%c%c%c", header->id[0], header->id[1], header->id[2]);
snprintf(IDfull, sizeof(IDfull), "%s%c%c%c", ID, header->id[3], header->id[4], header->id[5]);
for (int i = 0; i < 2; ++i)
{
char *coverPath = flag ? Settings.covers_path : Settings.covers2d_path;
flag = !flag;
//Load full id image
snprintf(Path, sizeof(Path), "%s%s.png", coverPath, IDfull);
delete Cover;
Cover = new (std::nothrow) GuiImageData(Path);
//Load short id image
if (!Cover || !Cover->GetImage())
{
snprintf(Path, sizeof(Path), "%s%s.png", coverPath, ID);
delete Cover;
Cover = new (std::nothrow) GuiImageData(Path);
}
if (Cover && Cover->GetImage()) break;
}
//Load no image
if (noCover && (!Cover || !Cover->GetImage()))
{
flag = Prefere3D;
for (int i = 0; i < 2; ++i)
{
flag = !flag;
delete Cover;
Cover = Resources::GetImageData(Prefere3D ? "nocover.png" : "nocoverFlat.png");
if (Cover && Cover->GetImage()) break;
}
}
if (Cover && !Cover->GetImage())
{
delete Cover;
Cover = NULL;
}
return Cover;
}
/****************************************************************************
* MainMenu
***************************************************************************/

View File

@ -34,7 +34,6 @@ enum
void ResumeGui();
void HaltGui();
GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D = true, bool noCover = true);
extern GuiImageData *pointer[4];
extern GuiImageData *background;

View File

@ -1,5 +1,6 @@
#include <unistd.h>
#include "GameBrowseMenu.hpp"
#include "libwiigui/LoadCoverImage.h"
#include "prompts/PromptWindows.h"
#include "prompts/gameinfo.h"
#include "prompts/DiscBrowser.h"
@ -22,6 +23,7 @@
#include "utils/rockout.h"
#include "utils/ShowError.h"
#include "utils/tools.h"
#include "utils/PasswordCheck.h"
#include "fatmounter.h"
#include "gecko.h"
#include "menus.h"
@ -539,18 +541,18 @@ void GameBrowseMenu::ReloadBrowser()
idBtn->SetToolTip(NULL, 0, 0);
}
if ((Settings.parentalcontrol == 0 && Settings.Parental.enabled == 1) && Settings.godmode)
if (Settings.godmode)
{
lockBtn->SetImage(unlockBtnImg);
lockBtn->SetImageOver(unlockBtnImg);
lockBtnTT->SetText(tr( "Unlock Parental Control" ));
GuiImage * unlockImage = strcmp(Settings.unlockCode, "") == 0 ? unlockBtnImg_g : unlockBtnImg;
lockBtn->SetImage(unlockImage);
lockBtn->SetImageOver(unlockImage);
lockBtnTT->SetText(tr( "Lock USB Loader GX" ));
}
else
{
GuiImage * lockImage = Settings.Parental.enabled ? lockBtnImg : lockBtnImg_g;
lockBtn->SetImage(lockImage);
lockBtn->SetImageOver(lockImage);
lockBtnTT->SetText(tr( "Parental Control disabled" ));
lockBtn->SetImage(lockBtnImg);
lockBtn->SetImageOver(lockBtnImg);
lockBtnTT->SetText(tr( "Unlock USB Loader GX" ));
}
if(GetSelectedGame() >= 0)
@ -948,15 +950,9 @@ int GameBrowseMenu::MainLoop()
{
gprintf("\tlockBtn clicked\n");
lockBtn->ResetState();
if (!(Settings.parentalcontrol == 0 && Settings.Parental.enabled == 1))
{
WindowPrompt(tr( "Parental Control" ), tr( "You don't have Parental Control enabled. If you wish to use Parental Control, enable it in the Wii Settings." ), tr( "OK" ));
return MENU_NONE;
}
if (Settings.godmode)
{
if(WindowPrompt(tr( "Parental Control" ), tr( "Are you sure you want to enable Parent Control?" ), tr( "Yes" ), tr( "No" )) == 1)
if(WindowPrompt(tr( "Parental Control" ), tr( "Are you sure you want to lock USB Loader GX?" ), tr( "Yes" ), tr( "No" )) == 1)
{
Settings.godmode = 0;
wString oldFilter(gameList.GetCurrentFilter());
@ -966,23 +962,21 @@ int GameBrowseMenu::MainLoop()
}
else
{
// Require the user to enter the PIN code
char pin[5];
memset(&pin, 0, 5);
int ret = OnScreenNumpad((char *) &pin, 5);
if (ret <= 0)
return MENU_NONE;
if (memcmp(pin, Settings.Parental.pin, 4) == 0)
//password check to unlock Install,Delete and Format
SetState(STATE_DISABLED);
int result = PasswordCheck(Settings.unlockCode);
SetState(STATE_DEFAULT);
if (result > 0)
{
if(result == 1)
WindowPrompt( tr( "Correct Password" ), tr( "All the features of USB Loader GX are unlocked." ), tr( "OK" ));
Settings.godmode = 1;
wString oldFilter(gameList.GetCurrentFilter());
gameList.FilterList(oldFilter.c_str());
ReloadBrowser();
}
else
WindowPrompt(tr( "Parental Control" ), tr( "Invalid PIN code" ), tr( "OK" ));
else if(result < 0)
WindowPrompt(tr( "Wrong Password" ), tr( "USB Loader GX is protected" ), tr( "OK" ));
}
}

View File

@ -118,7 +118,7 @@ int MountGamePartition(bool ShowGUI)
s32 wbfsinit = MountWBFS(ShowGUI);
if (wbfsinit < 0)
{
WindowPrompt(tr( "Error !" ), tr( "USB Device not found" ), tr( "OK" ));
if(ShowGUI) WindowPrompt(tr( "Error !" ), tr( "USB Device not found" ), tr( "OK" ));
Sys_LoadMenu();
}

View File

@ -32,6 +32,7 @@
#include "language/gettext.h"
#include "themes/CTheme.h"
#include "FileOperations/fileops.h"
#include "utils/encrypt.h"
CSettings Settings;
@ -66,7 +67,11 @@ void CSettings::SetDefault()
strcpy(language_path, "");
strcpy(ogg_path, "");
strcpy(unlockCode, "");
strcpy(db_url, "");
strcpy(db_language, "");
strcpy(returnTo, "");
godmode = 1;
videomode = VIDEO_MODE_DISCDEFAULT;
videopatch = OFF;
language = CONSOLE_DEFAULT;
@ -80,7 +85,7 @@ void CSettings::SetDefault()
gamesoundvolume = 80;
tooltips = ON;
gamesound = 1;
parentalcontrol = 0;
parentalcontrol = 4;
lockedgames = 0;
cios = 249;
xflip = XFLIP_NO;
@ -101,28 +106,7 @@ void CSettings::SetDefault()
InstallPartitions = ONLY_GAME_PARTITION;
fullcopy = 0;
beta_upgrades = 0;
strcpy(db_url, "");
strcpy(db_language, "");
strcpy(unlockCode, "");
strcpy(returnTo, "");
memset(&Parental, 0, sizeof(Parental));
char buf[0x4a];
s32 res = CONF_Get("IPL.PC", buf, 0x4A);
if (res > 0)
{
if (buf[2] != 0x14)
{
Parental.enabled = 1;
Parental.rating = buf[2];
}
Parental.question = buf[7];
memcpy(Parental.pin, buf + 3, 4);
memcpy(Parental.answer, buf + 8, 32);
}
widescreen = (CONF_GetAspectRatio() == CONF_ASPECT_16_9);
godmode = (Parental.enabled == 0) ? 1 : 0;
Theme.SetDefault(); //! We need to move this later
}
@ -187,7 +171,9 @@ bool CSettings::Save()
fprintf(file, "sfxvolume = %d\n ", sfxvolume);
fprintf(file, "gamesoundvolume = %d\n ", gamesoundvolume);
fprintf(file, "tooltips = %d\n ", tooltips);
fprintf(file, "password = %s\n ", unlockCode);
char EncryptedTxt[50];
EncryptString(unlockCode, EncryptedTxt);
fprintf(file, "password = %s\n ", EncryptedTxt);
fprintf(file, "GameSort = %d\n ", GameSort);
fprintf(file, "cios = %d\n ", cios);
fprintf(file, "keyset = %d\n ", keyset);
@ -243,7 +229,7 @@ bool CSettings::SetSetting(char *name, char *value)
{
if (sscanf(value, "%d", &i) == 1)
{
if(Parental.enabled) godmode = i;
godmode = i;
}
return true;
}
@ -337,7 +323,9 @@ bool CSettings::SetSetting(char *name, char *value)
}
else if (strcmp(name, "password") == 0)
{
strcpy(unlockCode, value);
char EncryptedTxt[50];
strcpy(EncryptedTxt, value);
DecryptString(EncryptedTxt, unlockCode);
return true;
}
else if (strcmp(name, "GameSort") == 0)

View File

@ -110,14 +110,6 @@ class CSettings
short fullcopy;
short beta_upgrades;
char returnTo[20];
struct
{
u8 enabled;
u8 rating;
u8 pin[4];
u8 question;
wchar_t answer[32]; // IS WCHAR!
} Parental;
protected:
bool SetSetting(char *name, char *value);
//!Find the config file in the default paths

View File

@ -2,6 +2,7 @@
#include "GameTitles.h"
#include "CSettings.h"
#include "usbloader/GameList.h"
#include "xml/xml.h"
#include "xml/WiiTDB.hpp"
CGameTitles GameTitles;
@ -61,6 +62,20 @@ const char * CGameTitles::GetTitle(const struct discHdr *header)
return header->title;
}
int CGameTitles::GetParentalRating(const char * id)
{
if(!id)
return -1;
for(u32 i = 0; i < TitleList.size(); ++i)
{
if(strncasecmp(id, TitleList[i].GameID, 6) == 0)
return TitleList[i].ParentalRating;
}
return -1;
}
void CGameTitles::SetDefault()
{
TitleList.clear();
@ -85,10 +100,25 @@ void CGameTitles::LoadTitlesFromWiiTDB(const char * path)
WiiTDB XML_DB(Filepath.c_str());
XML_DB.SetLanguageCode(Settings.db_language);
int Rating;
std::string RatValTxt;
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());
if(!XML_DB.GetTitle((const char *) gameList[i]->id, Title))
continue;
this->SetGameTitle(gameList[i]->id, Title.c_str());
TitleList[TitleList.size()-1].ParentalRating = -1;
Rating = XML_DB.GetRating((const char *) gameList[i]->id);
if(Rating < 0)
continue;
if(!XML_DB.GetRatingValue((const char *) gameList[i]->id, RatValTxt))
continue;
TitleList[TitleList.size()-1].ParentalRating = ConvertRating(RatValTxt.c_str(), WiiTDB::RatingToString(Rating), "PEGI");
}
}

View File

@ -10,6 +10,7 @@ typedef struct _GameTitle
{
char GameID[7];
std::string Title;
int ParentalRating;
} GameTitle;
@ -28,6 +29,9 @@ class CGameTitles
//! Overload
const char * GetTitle(const struct discHdr *header);
//! Get game parental rating
int GetParentalRating(const char * id);
//! Load Game Titles from WiiTDB
void LoadTitlesFromWiiTDB(const char * path);
//! Set default game titles

View File

@ -26,6 +26,7 @@
#include "settings/CSettings.h"
#include "prompts/PromptWindows.h"
#include "language/gettext.h"
#include "utils/PasswordCheck.h"
static const char * LockModeText[] =
{
@ -101,41 +102,27 @@ int ParentalControlSM::GetMenuInternal()
//! Settings: Console
if (ret == ++Idx)
{
if (strcmp(Settings.unlockCode, "") == 0 && !Settings.Parental.enabled)
if (!Settings.godmode)
{
Settings.godmode = !Settings.godmode;
}
else if (!Settings.godmode)
{
char entered[20];
memset(entered, 0, 20);
//password check to unlock Install,Delete and Format
SetState(STATE_DISABLED);
int result = Settings.Parental.enabled == 0 ? OnScreenKeyboard(entered, 20, 0) : OnScreenNumpad(entered, 5);
int result = PasswordCheck(Settings.unlockCode);
SetState(STATE_DEFAULT);
if (result == 1)
if (result > 0)
{
if (strcmp(entered, Settings.unlockCode) == 0 || !memcmp(entered, Settings.Parental.pin, 4)) //if password correct
{
WindowPrompt(
tr( "Correct Password" ),
tr( "All the features of USB Loader GX are unlocked." ),
tr( "OK" ));
Settings.godmode = 1;
}
else
WindowPrompt(tr( "Wrong Password" ), tr( "USB Loader GX is protected" ), tr( "OK" ));
if(result == 1)
WindowPrompt( tr( "Correct Password" ), tr( "All the features of USB Loader GX are unlocked." ), tr( "OK" ));
Settings.godmode = 1;
}
else if(result < 0)
WindowPrompt(tr( "Wrong Password" ), tr( "USB Loader GX is protected" ), tr( "OK" ));
}
else
{
int choice = WindowPrompt(tr( "Lock Console" ), tr( "Are you sure?" ),
tr( "Yes" ), tr( "No" ));
int choice = WindowPrompt(tr( "Lock Console" ), tr( "Are you sure?" ), tr( "Yes" ), tr( "No" ));
if (choice == 1)
{
WindowPrompt(tr( "Console Locked" ), tr( "USB Loader GX is protected" ),
tr( "OK" ));
WindowPrompt(tr( "Console Locked" ), tr( "USB Loader GX is protected" ), tr( "OK" ));
Settings.godmode = 0;
}
}

View File

@ -102,7 +102,7 @@ s32 IosLoader::LoadGameCios(s32 ios)
// Remount devices after reloading IOS.
SDCard_Init();
USBDevice_Init();
USBDevice_Init_Loop();
Disc_Init();
return ret;

View File

@ -155,18 +155,12 @@ int GameList::FilterList(const wchar_t * gameFilter)
}
/* Rating based parental control method */
if (Settings.parentalcontrol == 0 && Settings.godmode == 0 && Settings.Parental.enabled == 1)
if (Settings.parentalcontrol != 4 && Settings.godmode == 0)
{
// Check game rating in WiiTDB, since the default Wii parental control setting is enabled
s32 rating = GetRatingForGame((char *) header->id);
if ((rating != -1 && rating > Settings.Parental.rating) ||
(GameConfig && rating == -1 &&
CGameSettings::GetPartenalPEGI(GameConfig->parentalcontrol)
> Settings.Parental.rating))
{
int rating = GameTitles.GetParentalRating((char *) header->id);
if (rating > Settings.parentalcontrol)
continue;
}
}
//! Per game lock method

View File

@ -380,7 +380,7 @@ s32 Partition_GetList(u32 device, PartList *plist)
//if (!part_is_data(entry->type)) continue;
if (!Device_ReadSectors(device, entry->sector, 1, buf)) continue;
pinfo->fs_type = get_fs_type((u8 *) buf);
if(entry->type == 0x83) pinfo->fs_type = FS_TYPE_EXT;
if(entry->type == 0x83 && pinfo->fs_type == FS_TYPE_UNK) pinfo->fs_type = FS_TYPE_EXT;
if (pinfo->fs_type == FS_TYPE_WBFS)
{
// multiple wbfs on sdhc not supported

View File

@ -69,32 +69,20 @@ s32 WBFS_OpenPart(u32 part_fs, u32 part_idx, u32 part_lba, u32 part_size, char *
{
current = new Wbfs_Fat(wbfsDev, part_lba, part_size);
strcpy(wbfs_fs_drive, "USB:");
#ifdef DEBUG_WBFS
gprintf("\n\tCreated WBFS_Fat instance at lba: %d of size %d", part_lba, part_size);
#endif
}
else if (part_fs == PART_FS_NTFS)
{
current = new Wbfs_Ntfs(wbfsDev, part_lba, part_size);
strcpy(wbfs_fs_drive, "NTFS:");
#ifdef DEBUG_WBFS
gprintf("\n\tCreated WBFS_Ntfs instance at lba: %d of size %d", part_lba, part_size);
#endif
}
else if (part_fs == PART_FS_EXT)
{
current = new Wbfs_Ext(wbfsDev, part_lba, part_size);
strcpy(wbfs_fs_drive, "EXT:");
#ifdef DEBUG_WBFS
gprintf("\n\tCreated WBFS_Ext instance at lba: %d of size %d", part_lba, part_size);
#endif
}
else
{
current = new Wbfs_Wbfs(wbfsDev, part_lba, part_size);
#ifdef DEBUG_WBFS
gprintf("\n\tCreated WBFS_Wbfs instance at lba: %d of size %d", part_lba, part_size);
#endif
}
if (current->Open())
{

View File

@ -0,0 +1,21 @@
#include "prompts/PromptWindows.h"
int PasswordCheck(const char * password)
{
if(!password || strcmp(password, "") == 0 || strcmp(password, "not set") == 0)
return 2;
char entered[100];
memset(entered, 0, sizeof(entered));
int result = OnScreenKeyboard(entered, 20, 0);
if (result == 1)
{
if (strcmp(entered, password) == 0) //if password correct
return 1;
else
return -1;
}
return 0;
}

View File

@ -0,0 +1,6 @@
#ifndef PASSWORD_CHECK_H_
#define PASSWORD_CHECK_H_
int PasswordCheck(const char * password);
#endif

57
source/utils/encrypt.c Normal file
View File

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2010
* by dude, 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 <stdio.h>
#include <string.h>
//! No need for high security crap. It's a simple encrypter/decrypter
//! with a constant sid.
const char * sid = "USBLoaderGX";
void EncryptString(const char *src, char *dst)
{
int i;
char tmp[3];
dst[0] = 0;
for (i = 0; i < strlen(src); i++)
{
sprintf(tmp, "%02x", src[i] ^ sid[i%10]);
strcat(dst, tmp);
}
}
void DecryptString(const char *src, char *dst)
{
int i;
for (i = 0; i < strlen(src); i += 2)
{
char c = (src[i] >= 'a' ? (src[i] - 'a') + 10 : (src[i] - '0')) << 4;
c += (src[i+1] >= 'a' ? (src[i+1] - 'a') + 10 : (src[i+1] - '0'));
dst[i>>1] = c ^ sid[(i>>1)%10];
}
dst[strlen(src)>>1] = 0;
}

41
source/utils/encrypt.h Normal file
View File

@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2010
* by dude
*
* 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 __ENCRYPT_H
#define __ENCRYPT_H
#ifdef __cplusplus
extern "C" {
#endif
void EncryptString(const char *src, char *dst);
void DecryptString(const char *src, char *dst);
#ifdef __cplusplus
}
#endif //__cplusplus
#endif /* __ENCRYPT_H */

View File

@ -13,27 +13,10 @@
extern char game_partition[6];
static char * trimcopy(char *dest, char *src, int size)
{
int len;
while (*src == ' ')
src++;
len = strlen(src);
// trim trailing " \r\n"
while (len > 0 && strchr(" \r\n", src[len - 1]))
len--;
if (len >= size) len = size - 1;
strlcpy(dest, src, len + 1);
return dest;
}
/* 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" } };
@ -128,7 +111,6 @@ bool OpenXMLFile(char *filename)
if (xml_loaded) return false;
gameinfo = gameinfo_reset;
nodedata = NULL;
nodetree = NULL;
nodeid = NULL;
@ -245,40 +227,70 @@ char ConvertRatingToIndex(char *ratingtext)
return type;
}
void ConvertRating(char *ratingvalue, char *fromrating, const char *torating, char *destvalue, int destsize)
int ConvertRating(const char *ratingvalue, const char *fromrating, const char *torating)
{
if (!strcmp(fromrating, torating))
{
strlcpy(destvalue, ratingvalue, destsize);
return;
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;
}
strcpy(destvalue, "");
int type = -1;
int desttype = -1;
type = ConvertRatingToIndex(fromrating);
type = ConvertRatingToIndex((char *) fromrating);
desttype = ConvertRatingToIndex((char *) torating);
if (type == -1 || desttype == -1) return;
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" } }, };
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;
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;
}
void LoadTitlesFromXML(char *langtxt, bool forcejptoen)
@ -388,388 +400,6 @@ void GetPublisherFromGameid(char *idtxt, char *dest, int destsize)
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] = "";
@ -819,43 +449,3 @@ char * get_nodetext(mxml_node_t *node, char *buffer, int buflen) /* O - Text in
*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;
}

View File

@ -6,61 +6,17 @@
// open database, close database, load info for a game
bool OpenXMLDatabase(char* xmlfilepath, char* argdblang, bool argJPtoEN, bool openfile, bool loadtitles, bool keepopen);
void CloseXMLDatabase();
bool LoadGameInfoFromXML(char* gameid, char* langcode);
#define XML_ELEMMAX 15
#define XML_SYNOPSISLEN 4000
struct gameXMLinfo
{
char id[7];
char version[50];
char region[7];
char title[200];
char synopsis[XML_SYNOPSISLEN];
char title_EN[200];
char synopsis_EN[XML_SYNOPSISLEN];
char locales[XML_ELEMMAX + 1][5];
int localeCnt;
char developer[75];
char publisher[75];
char publisherfromid[75];
char year[5];
char month[3];
char day[3];
char genre[75];
char genresplit[XML_ELEMMAX + 1][20];
int genreCnt;
char ratingtype[5];
char ratingvalue[5];
char ratingdescriptors[XML_ELEMMAX + 1][40];
int descriptorCnt;
char ratingvalueCERO[5];
char ratingvalueESRB[5];
char ratingvaluePEGI[5];
char wifiplayers[4];
char wififeatures[XML_ELEMMAX + 1][20];
int wifiCnt;
char players[4];
char accessories[XML_ELEMMAX + 1][20];
int accessoryCnt;
char accessoriesReq[XML_ELEMMAX + 1][20];
int accessoryReqCnt;
char iso_crc[9];
char iso_md5[33];
char iso_sha1[41];
};
bool OpenXMLFile(char* filename);
void LoadTitlesFromXML(char *langcode, bool forcejptoen);
void GetPublisherFromGameid(char *idtxt, char *dest, int destsize);
const char *ConvertLangTextToCode(char *langtext);
void ConvertRating(char *ratingvalue, char *fromrating, const char *torating, char *destvalue, int destsize);
void PrintGameInfo(bool showfullinfo);
int ConvertRating(const char *ratingvalue, const char *fromrating, const char *torating);
char *MemInfo();
void GetTextFromNode(mxml_node_t *currentnode, mxml_node_t *topnode, const char *nodename, const char *attributename,
char *value, int descend, char *dest, int destsize);
int GetRatingForGame(char *gameid);
char * get_nodetext(mxml_node_t *node, char *buffer, int buflen);
#endif