diff --git a/HBC/META.XML b/HBC/META.XML index 50b4f71f..e54d45a5 100644 --- a/HBC/META.XML +++ b/HBC/META.XML @@ -2,8 +2,8 @@ USB Loader GX USB Loader GX Team - 1.0 r1010 - 201012051910 + 1.0 r1015 + 201012181321 Loads games from USB-devices 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. diff --git a/gui.pnproj b/gui.pnproj index 5a167df4..1e690d9b 100644 --- a/gui.pnproj +++ b/gui.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/FileOperations/DirList.cpp b/source/FileOperations/DirList.cpp index d18bbd00..c6184613 100644 --- a/source/FileOperations/DirList.cpp +++ b/source/FileOperations/DirList.cpp @@ -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; diff --git a/source/libwiigui/LoadCoverImage.cpp b/source/libwiigui/LoadCoverImage.cpp new file mode 100644 index 00000000..0d3dde0b --- /dev/null +++ b/source/libwiigui/LoadCoverImage.cpp @@ -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; +} diff --git a/source/libwiigui/LoadCoverImage.h b/source/libwiigui/LoadCoverImage.h new file mode 100644 index 00000000..dae4283c --- /dev/null +++ b/source/libwiigui/LoadCoverImage.h @@ -0,0 +1,6 @@ +#ifndef LOADCOVERIMAGE_H_ +#define LOADCOVERIMAGE_H_ + +GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D = true, bool noCover = true); + +#endif diff --git a/source/libwiigui/gui_gamecarousel.cpp b/source/libwiigui/gui_gamecarousel.cpp index bd8e5ca8..b2435b32 100644 --- a/source/libwiigui/gui_gamecarousel.cpp +++ b/source/libwiigui/gui_gamecarousel.cpp @@ -7,17 +7,18 @@ ***************************************************************************/ #include "gui.h" -#include "../wpad.h" -#include "../menu.h" +#include "wpad.h" +#include "menu.h" #include #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 #include @@ -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; } diff --git a/source/libwiigui/gui_gamecarousel.h b/source/libwiigui/gui_gamecarousel.h index 8f8320e3..489a98dc 100644 --- a/source/libwiigui/gui_gamecarousel.h +++ b/source/libwiigui/gui_gamecarousel.h @@ -1,8 +1,9 @@ #ifndef _GUIGAMECAROUSEL_H_ #define _GUIGAMECAROUSEL_H_ +#include #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 game; + std::vector coverImg; GuiText * gamename; diff --git a/source/libwiigui/gui_gamegrid.cpp b/source/libwiigui/gui_gamegrid.cpp index b85dbeda..ad31688f 100644 --- a/source/libwiigui/gui_gamegrid.cpp +++ b/source/libwiigui/gui_gamegrid.cpp @@ -7,18 +7,19 @@ ***************************************************************************/ #include "gui.h" -#include "../wpad.h" +#include "wpad.h" #include #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 @@ -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); diff --git a/source/libwiigui/gui_gamegrid.h b/source/libwiigui/gui_gamegrid.h index 4279a0bc..c6ea4d99 100644 --- a/source/libwiigui/gui_gamegrid.h +++ b/source/libwiigui/gui_gamegrid.h @@ -1,8 +1,10 @@ #ifndef _GUIGAMEGRID_H_ #define _GUIGAMEGRID_H_ +#include #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 game; + std::vector titleTT; + std::vector coverImg; GuiButton * btnRight; GuiButton * btnLeft; diff --git a/source/libwiigui/gui_image_async.cpp b/source/libwiigui/gui_image_async.cpp index ff08d800..a2ad15ad 100644 --- a/source/libwiigui/gui_image_async.cpp +++ b/source/libwiigui/gui_image_async.cpp @@ -1,187 +1,149 @@ /**************************************************************************** - * libwiigui - * - * Tantric 2009 + * USB Loader GX * * gui_imagea_sync.cpp - * - * GUI class definitions ***************************************************************************/ - -#include "gui.h" -//#include #include #include "gui_image_async.h" -static mutex_t debugLock = LWP_MUTEX_NULL; -void debug(int Line, const char* Format, ...) +std::vector 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 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); can’t 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::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; } diff --git a/source/libwiigui/gui_image_async.h b/source/libwiigui/gui_image_async.h index b003d5d9..3f440b4a 100644 --- a/source/libwiigui/gui_image_async.h +++ b/source/libwiigui/gui_image_async.h @@ -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 +#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 List; + static lwp_t Thread; + static mutex_t ListLock; + static GuiImageAsync * InUse; + static u32 ThreadCount; + static bool ThreadSleep; + static bool CloseThread; }; #endif /*_GUIIMAGEASYNC_H_*/ diff --git a/source/menu.cpp b/source/menu.cpp index 42544ba2..1557187e 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -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 ***************************************************************************/ diff --git a/source/menu.h b/source/menu.h index d79f0b05..e9cee0b0 100644 --- a/source/menu.h +++ b/source/menu.h @@ -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; diff --git a/source/menu/GameBrowseMenu.cpp b/source/menu/GameBrowseMenu.cpp index 23c34d20..9dca35b1 100644 --- a/source/menu/GameBrowseMenu.cpp +++ b/source/menu/GameBrowseMenu.cpp @@ -1,5 +1,6 @@ #include #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" )); } } diff --git a/source/menu/MountGamePartition.cpp b/source/menu/MountGamePartition.cpp index dee8df9a..da890fbc 100644 --- a/source/menu/MountGamePartition.cpp +++ b/source/menu/MountGamePartition.cpp @@ -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(); } diff --git a/source/settings/CSettings.cpp b/source/settings/CSettings.cpp index 600a5c87..059736a6 100644 --- a/source/settings/CSettings.cpp +++ b/source/settings/CSettings.cpp @@ -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) diff --git a/source/settings/CSettings.h b/source/settings/CSettings.h index c41c9073..6a979085 100644 --- a/source/settings/CSettings.h +++ b/source/settings/CSettings.h @@ -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 diff --git a/source/settings/GameTitles.cpp b/source/settings/GameTitles.cpp index 6c6d9b1b..1396ab5b 100644 --- a/source/settings/GameTitles.cpp +++ b/source/settings/GameTitles.cpp @@ -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"); } } diff --git a/source/settings/GameTitles.h b/source/settings/GameTitles.h index f27ed95d..ef8f9def 100644 --- a/source/settings/GameTitles.h +++ b/source/settings/GameTitles.h @@ -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 diff --git a/source/settings/menus/ParentalControlSM.cpp b/source/settings/menus/ParentalControlSM.cpp index c665dc1b..6b4dd9a1 100644 --- a/source/settings/menus/ParentalControlSM.cpp +++ b/source/settings/menus/ParentalControlSM.cpp @@ -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; } } diff --git a/source/system/IosLoader.cpp b/source/system/IosLoader.cpp index 045b0f66..dafad527 100644 --- a/source/system/IosLoader.cpp +++ b/source/system/IosLoader.cpp @@ -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; diff --git a/source/usbloader/GameList.cpp b/source/usbloader/GameList.cpp index 74a902e4..ef654b49 100644 --- a/source/usbloader/GameList.cpp +++ b/source/usbloader/GameList.cpp @@ -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 diff --git a/source/usbloader/partition_usbloader.c b/source/usbloader/partition_usbloader.c index 17dd257a..52974067 100644 --- a/source/usbloader/partition_usbloader.c +++ b/source/usbloader/partition_usbloader.c @@ -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 diff --git a/source/usbloader/wbfs.cpp b/source/usbloader/wbfs.cpp index 33beca6a..4b0131a2 100644 --- a/source/usbloader/wbfs.cpp +++ b/source/usbloader/wbfs.cpp @@ -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()) { diff --git a/source/utils/PasswordCheck.cpp b/source/utils/PasswordCheck.cpp new file mode 100644 index 00000000..a0ceb595 --- /dev/null +++ b/source/utils/PasswordCheck.cpp @@ -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; +} diff --git a/source/utils/PasswordCheck.h b/source/utils/PasswordCheck.h new file mode 100644 index 00000000..9df6cc22 --- /dev/null +++ b/source/utils/PasswordCheck.h @@ -0,0 +1,6 @@ +#ifndef PASSWORD_CHECK_H_ +#define PASSWORD_CHECK_H_ + +int PasswordCheck(const char * password); + +#endif diff --git a/source/utils/encrypt.c b/source/utils/encrypt.c new file mode 100644 index 00000000..52fbf5f7 --- /dev/null +++ b/source/utils/encrypt.c @@ -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 +#include + +//! 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; +} + diff --git a/source/utils/encrypt.h b/source/utils/encrypt.h new file mode 100644 index 00000000..6c8139de --- /dev/null +++ b/source/utils/encrypt.h @@ -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 */ + diff --git a/source/xml/xml.cpp b/source/xml/xml.cpp index 95ad652c..2d62def1 100644 --- a/source/xml/xml.cpp +++ b/source/xml/xml.cpp @@ -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; -} diff --git a/source/xml/xml.h b/source/xml/xml.h index 2bb09ee1..cd40b089 100644 --- a/source/xml/xml.h +++ b/source/xml/xml.h @@ -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