Lots of changes in this revision:

* Added MEM2 support by Hibern
* Better partition support (by oggzee)
* Support for subdirectories in FAT32 (by oggzee)
* Added support for cios 223 and 250
* Added BCA support (go to Settings->Custom Paths) to change the path of the BCA files (by Hermes)
* Fixed issue with hairless mode
* Fixed issue with IOS_ReloadIOSsafe (by giantpune)
* Added setting to save games in a subdirectory
* Fixed slow startup when loading from FAT (WiiTDB required!)
* Changed handling of new titles a bit (speed improvement)

Known issue:
* FAT rename and re-id broken again due to subdirectory support (yes, I'm lazy)
This commit is contained in:
e.bovendeur 2009-12-04 15:05:20 +00:00
parent d14bebd159
commit 2543c555a4
37 changed files with 1444 additions and 454 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>1.0 r846</version> <version>1.0 r847</version>
<release_date>200912030606</release_date> <release_date>200912031841</release_date>
<short_description>Loads games from USB-devices</short_description> <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. <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. The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.

View File

@ -20,7 +20,7 @@ SOURCES := source source/libwiigui source/images source/fonts source/sounds \
source/libwbfs source/unzip source/language source/mload source/patches \ source/libwbfs source/unzip source/language source/mload source/patches \
source/usbloader source/xml source/network source/settings source/prompts \ source/usbloader source/xml source/network source/settings source/prompts \
source/ramdisk source/wad source/banner source/cheats source/homebrewboot \ source/ramdisk source/wad source/banner source/cheats source/homebrewboot \
source/themes source/menu source/libfat source/themes source/menu source/libfat source/memory
DATA := data DATA := data
INCLUDES := source INCLUDES := source
@ -30,8 +30,9 @@ INCLUDES := source
CFLAGS = -g -O2 -save-temps -Wall $(MACHDEP) $(INCLUDE) CFLAGS = -g -O2 -save-temps -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS = -Xassembler -aln=$@.lst $(CFLAGS) CXXFLAGS = -Xassembler -aln=$@.lst $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00000 LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00000,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size
-include $(PROJECTDIR)/Make.config -include $(PROJECTDIR)/Make.config
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project # any extra libraries we wish to link with the project
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

Binary file not shown.

View File

@ -1 +1 @@
<pd><ViewState><e p="gui\source\mload" x="false"></e><e p="gui\source\settings" x="true"></e><e p="gui\source\images" x="false"></e><e p="gui\source\libfat" x="false"></e><e p="gui\source\prompts" x="false"></e><e p="gui\source\banner" x="false"></e><e p="gui\source\cheats" x="false"></e><e p="gui\source\network" x="false"></e><e p="gui\source\unzip" x="false"></e><e p="gui\source\usbloader" x="true"></e><e p="gui\source\xml" x="false"></e><e p="gui\source\fonts" x="false"></e><e p="gui\source\menu" x="false"></e><e p="gui\source\ramdisk" x="false"></e><e p="gui\source\sounds" x="false"></e><e p="gui\source\wad" x="false"></e><e p="gui" x="true"></e><e p="gui\source\homebrewboot" x="false"></e><e p="gui\source\language" x="false"></e><e p="gui\source" x="true"></e><e p="gui\source\libwbfs" x="false"></e><e p="gui\source\libwiigui" x="false"></e><e p="gui\source\patches" x="false"></e><e p="gui\source\themes" x="false"></e></ViewState></pd> <pd><ViewState><e p="gui\source\mload" x="false"></e><e p="gui\source\settings" x="false"></e><e p="gui\source\images" x="false"></e><e p="gui\source\libfat" x="false"></e><e p="gui\source\prompts" x="true"></e><e p="gui\source\banner" x="false"></e><e p="gui\source\cheats" x="false"></e><e p="gui\source\network" x="false"></e><e p="gui\source\fonts" x="false"></e><e p="gui\source\menu" x="false"></e><e p="gui\source\ramdisk" x="false"></e><e p="gui\source\sounds" x="false"></e><e p="gui\source\wad" x="false"></e><e p="gui" x="true"></e><e p="gui\source\homebrewboot" x="false"></e><e p="gui\source\language" x="false"></e><e p="gui\source" x="true"></e><e p="gui\source\libwbfs" x="false"></e><e p="gui\source\libwiigui" x="false"></e><e p="gui\source\patches" x="false"></e><e p="gui\source\themes" x="false"></e><e p="gui\source\memory" x="false"></e><e p="gui\source\unzip" x="false"></e><e p="gui\source\usbloader" x="false"></e><e p="gui\source\xml" x="false"></e></ViewState></pd>

View File

@ -13,6 +13,7 @@
#include "gui_gamebrowser.h" #include "gui_gamebrowser.h"
#include "../settings/cfg.h" #include "../settings/cfg.h"
#include "../main.h" #include "../main.h"
#include "settings/newtitles.h"
#include <string.h> #include <string.h>
#include <sstream> #include <sstream>
@ -341,14 +342,15 @@ void GuiGameBrowser::UpdateListEntries()
gameTxtOver[i]->SetPosition(24, 0); gameTxtOver[i]->SetPosition(24, 0);
if (Settings.marknewtitles) { if (Settings.marknewtitles) {
if (gameList[next].isNew) { bool isNew = NewTitles::Instance()->IsNew(gameList[next].id);
if (isNew) {
gameTxt[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::DOTTED); gameTxt[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::DOTTED);
gameTxtOver[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::SCROLL); gameTxtOver[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), GuiText::SCROLL);
} else { } else {
gameTxt[i]->SetMaxWidth(maxTextWidth, GuiText::DOTTED); gameTxt[i]->SetMaxWidth(maxTextWidth, GuiText::DOTTED);
gameTxtOver[i]->SetMaxWidth(maxTextWidth, GuiText::SCROLL); gameTxtOver[i]->SetMaxWidth(maxTextWidth, GuiText::SCROLL);
} }
newImg[i]->SetVisible(gameList[next].isNew != 0); newImg[i]->SetVisible(isNew);
} }
gameIndex[i] = next; gameIndex[i] = next;

View File

@ -50,6 +50,7 @@
#include "wad/title.h" #include "wad/title.h"
#include "usbloader/partition_usbloader.h" #include "usbloader/partition_usbloader.h"
#include "usbloader/usbstorage.h" #include "usbloader/usbstorage.h"
#include "memory/mem2.h"
extern bool geckoinit; extern bool geckoinit;
extern bool textVideoInit; extern bool textVideoInit;
@ -177,7 +178,7 @@ void InitTextVideo () {
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
// InitTextVideo(); InitTextVideo();
//DEBUG_Init(GDBSTUB_DEVICE_USB, 1); //DEBUG_Init(GDBSTUB_DEVICE_USB, 1);
//_break(); //_break();
@ -195,8 +196,17 @@ main(int argc, char *argv[]) {
gprintf(", %s",argv[i]?argv[i]:"<NULL>"); gprintf(", %s",argv[i]?argv[i]:"<NULL>");
gprintf(")"); gprintf(")");
// This part is added, because we need a identify patched ios
printf("\n\tReloading into ios 236");
if (IOS_ReloadIOSsafe(236) < 0) {
printf("\n\tIOS 236 not found, reloading into 36");
IOS_ReloadIOSsafe(36);
}
printf("\n\tStarting up"); printf("\n\tStarting up");
MEM2_init(36); // Initialize 36 MB
MEM2_takeBigOnes(true);
s32 ret; s32 ret;
bool startupproblem = false; bool startupproblem = false;
@ -228,15 +238,25 @@ main(int argc, char *argv[]) {
{ {
InitTextVideo(); InitTextVideo();
printf("\x1b[2J"); printf("\x1b[2J");
printf("\n\n\n\tERROR!"); if ((ios222rev < 0 && ios222rev != WII_EINSTALL) || (ios249rev < 0 && ios249rev != WII_EINSTALL)) {
printf("\n\tUSB Loader GX needs unstubbed cIOS 222 v4 or 249 v9+"); printf("\n\n\n\tWARNING!");
printf("\n\n\tI found \n\t\t222 = %d%s",ios222rev,ios222rev==65535?" (Stubbed by 4.2 update)":""); printf("\n\tUSB Loader GX needs unstubbed cIOS 222 v4 or 249 v9+");
printf("\n\t\t249 = %d%s",ios249rev,ios249rev==65535?" (Stubbed by 4.2 update)":""); printf("\n\n\tWe cannot determine the versions on your system,\n\tsince you have no patched ios 36 or 236 installed.");
printf("\n\n\tGo figure out how to get some cIOS action going on\n\tin your Wii and come back and see me."); printf("\n\tTherefor, if loading of USB Loader GX fails, you\n\tprobably have installed the 4.2 update,");
printf("\n\tand you should go figure out how to get some cios action going on\n\tin your Wii.");
sleep(15); printf("\n\n\tThis message will show every time.");
printf("\n\n\tBye"); sleep(5);
exit(0); } else {
printf("\n\n\n\tERROR!");
printf("\n\tUSB Loader GX needs unstubbed cIOS 222 v4 or 249 v9+");
printf("\n\n\tI found \n\t\t222 = %d%s",ios222rev,ios222rev==65535?" (Stubbed by 4.2 update)":"");
printf("\n\t\t249 = %d%s",ios249rev,ios249rev==65535?" (Stubbed by 4.2 update)":"");
printf("\n\n\tGo figure out how to get some cIOS action going on\n\tin your Wii and come back and see me.");
sleep(15);
printf("\n\n\tBye");
exit(0);
}
} }
printf("\n\tReloading ios 249..."); printf("\n\tReloading ios 249...");
@ -248,11 +268,24 @@ main(int argc, char *argv[]) {
printf("\n\tIOS 249 failed, reloading ios 222..."); printf("\n\tIOS 249 failed, reloading ios 222...");
ret = IOS_ReloadIOSsafe(222); ret = IOS_ReloadIOSsafe(222);
printf("%d", ret); printf("%d", ret);
if(ret < 0) {
printf("\n\tERROR: cIOS could not be loaded!\n"); if (ret < 0) {
sleep(5); printf("\n\tIOS 222 failed, reloading ios 250...");
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); ret = IOS_ReloadIOSsafe(250);
} printf("%d", ret);
if(ret < 0) {
printf("\n\tIOS 250 failed, reloading ios 223...");
ret = IOS_ReloadIOSsafe(223);
printf("%d", ret);
if (ret < 0) {
printf("\n\tERROR: cIOS could not be loaded!\n");
sleep(5);
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
}
}
}
printf("\n\tInitialize sd card"); printf("\n\tInitialize sd card");
SDCard_Init(); SDCard_Init();
printf("\n\tLoad ehc module"); printf("\n\tLoad ehc module");
@ -327,12 +360,13 @@ main(int argc, char *argv[]) {
// gprintf("\n\tbootDevice = %s",bootDevice); // gprintf("\n\tbootDevice = %s",bootDevice);
/* Load Custom IOS */ /* Load Custom IOS */
if (Settings.cios == ios222 && IOS_GetVersion() != 222) { if ((Settings.cios == ios222 && IOS_GetVersion() != 222) ||
printf("\n\tReloading IOS to config setting (222)..."); (Settings.cios == ios223 && IOS_GetVersion() != 223)) {
printf("\n\tReloading IOS to config setting (%d)...", ios222 ? 222 : 223);
SDCard_deInit();// unmount SD for reloading IOS SDCard_deInit();// unmount SD for reloading IOS
USBDevice_deInit();// unmount USB for reloading IOS USBDevice_deInit();// unmount USB for reloading IOS
USBStorage_Deinit(); USBStorage_Deinit();
ret = IOS_ReloadIOSsafe(222); ret = IOS_ReloadIOSsafe(ios222 ? 222 : 223);
printf("%d", ret); printf("%d", ret);
SDCard_Init(); SDCard_Init();
load_ehc_module(); load_ehc_module();
@ -344,12 +378,14 @@ main(int argc, char *argv[]) {
SDCard_Init(); // now mount SD:/ SDCard_Init(); // now mount SD:/
USBDevice_Init(); // and mount USB:/ USBDevice_Init(); // and mount USB:/
WBFS_Init(WBFS_DEVICE_USB); WBFS_Init(WBFS_DEVICE_USB);
} else if (Settings.cios == ios249 && IOS_GetVersion() != 249) { } else if ((Settings.cios == ios249 && IOS_GetVersion() != 249) ||
printf("\n\tReloading IOS to config setting (249)..."); (Settings.cios == ios250 && IOS_GetVersion() != 250)) {
printf("\n\tReloading IOS to config setting (%d)...", ios249 ? 249 : 250);
SDCard_deInit();// unmount SD for reloading IOS SDCard_deInit();// unmount SD for reloading IOS
USBDevice_deInit();// unmount USB for reloading IOS USBDevice_deInit();// unmount USB for reloading IOS
USBStorage_Deinit(); USBStorage_Deinit();
ret = IOS_ReloadIOSsafe(249); ret = IOS_ReloadIOSsafe(ios249 ? 249 : 250);
printf("%d", ret); printf("%d", ret);
if (ret < 0) { if (ret < 0) {
Settings.cios = ios222; Settings.cios = ios222;
@ -377,9 +413,9 @@ main(int argc, char *argv[]) {
//if a ID was passed via args copy it and try to boot it after the partition is mounted //if a ID was passed via args copy it and try to boot it after the partition is mounted
//its not really a headless mode. more like hairless. //its not really a headless mode. more like hairless.
if (argc>0&&argv[1]) if (argc > 1 && argv[1])
{ {
strcpy(headlessID,argv[1]); strncpy(headlessID, argv[1], sizeof(headlessID));
} }
//! Init the rest of the System //! Init the rest of the System

213
source/memory/mem2.cpp Normal file
View File

@ -0,0 +1,213 @@
#include "mem2.h"
#include "mem2alloc.h"
#include "gecko.h"
#include <malloc.h>
#include <string.h>
#define MEM2_PRIORITY_SIZE 0x40
// Forbid the use of MEM2 through malloc
u32 MALLOC_MEM2 = 0;
static CMEM2Alloc g_mem2gp;
void MEM2_init(unsigned int mem2Size)
{
g_mem2gp.init(mem2Size);
}
void MEM2_cleanup(void)
{
g_mem2gp.cleanup();
}
extern "C" void *MEM2_alloc(unsigned int s)
{
return g_mem2gp.allocate(s);
}
extern "C" void MEM2_free(void *p)
{
g_mem2gp.release(p);
}
extern "C" void *MEM2_realloc(void *p, unsigned int s)
{
return g_mem2gp.reallocate(p, s);
}
extern "C" unsigned int MEM2_usableSize(void *p)
{
return CMEM2Alloc::usableSize(p);
}
// Give priority to MEM2 for big allocations
// Used for saving some space in malloc, which is required for 2 reasons :
// - decent speed on small and frequent allocations
// - newlib uses its malloc internally (for *printf for example) so it should always have some memory left
bool g_bigGoesToMem2 = false;
void MEM2_takeBigOnes(bool b)
{
g_bigGoesToMem2 = b;
}
extern "C"
{
extern __typeof(malloc) __real_malloc;
extern __typeof(calloc) __real_calloc;
extern __typeof(realloc) __real_realloc;
extern __typeof(memalign) __real_memalign;
extern __typeof(free) __real_free;
extern __typeof(malloc_usable_size) __real_malloc_usable_size;
void *__wrap_malloc(size_t size)
{
void *p;
if (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)
{
p = MEM2_alloc(size);
if (p != 0) {
gprintf("Malloc of size %d returns address in MEM2\n", size);
return p;
}
gprintf("Malloc of size %d returns address in MEM1\n", size);
return __real_malloc(size);
}
p = __real_malloc(size);
if (p != 0) {
gprintf("Malloc of size %d returns address in MEM1\n", size);
return p;
}
gprintf("Malloc of size %d returns address in MEM2\n", size);
return MEM2_alloc(size);
}
void *__wrap_calloc(size_t n, size_t size)
{
void *p;
if (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)
{
p = MEM2_alloc(n * size);
if (p != 0)
{
gprintf("Calloc of amount %d, size %d returns address in MEM2\n", n, size);
memset(p, 0, n * size);
return p;
}
gprintf("Calloc of amount %d, size %d returns address in MEM1\n", n, size);
return __real_calloc(n, size);
}
p = __real_calloc(n, size);
if (p != 0) {
gprintf("Calloc of amount %d, size %d returns address in MEM1\n", n, size);
return p;
}
p = MEM2_alloc(n * size);
if (p != 0) {
gprintf("Calloc of amount %d, size %d returns address in MEM2\n", n, size);
memset(p, 0, n * size);
} else {
gprintf("Calloc of amount %d, size %d returns NULL\n", n, size);
}
return p;
}
void *__wrap_memalign(size_t a, size_t size)
{
void *p;
if (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)
{
if (a <= 32 && 32 % a == 0)
{
p = MEM2_alloc(size);
if (p != 0) {
gprintf("Memalign in blocks of %d, size %d returns address in MEM2\n", a, size);
return p;
}
}
gprintf("Memalign in blocks of %d, size %d returns address in MEM1\n", a, size);
return __real_memalign(a, size);
}
p = __real_memalign(a, size);
if (p != 0 || a > 32 || 32 % a != 0) {
gprintf("Memalign in blocks of %d, size %d returns address in MEM1\n", a, size);
return p;
}
p = MEM2_alloc(size);
if (p != 0) {
gprintf("Memalign in blocks of %d, size %d returns address in MEM2\n", a, size);
} else {
gprintf("Memalign in blocks of %d, size %d returns NULL\n", a, size);
}
return p;
}
void __wrap_free(void *p)
{
if (((u32)p & 0x10000000) != 0) {
gprintf("Free pointer in address in MEM2\n");
MEM2_free(p);
} else {
gprintf("Free pointer in address in MEM1\n");
__real_free(p);
}
}
void *__wrap_realloc(void *p, size_t size)
{
void *n;
// ptr from mem2
if (((u32)p & 0x10000000) != 0 || (p == 0 && g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE))
{
n = MEM2_realloc(p, size);
if (n != 0) {
gprintf("Realloc of size %d returns memory in MEM2\n", size);
return n;
}
n = __real_malloc(size);
if (n == 0) {
gprintf("Realloc of size %d returns NULL\n", size);
return 0;
}
if (p != 0)
{
memcpy(n, p, MEM2_usableSize(p) < size ? MEM2_usableSize(p) : size);
MEM2_free(p);
}
gprintf("Realloc of size %d returns memory in MEM1\n", size);
return n;
}
// ptr from malloc
n = __real_realloc(p, size);
if (n != 0) {
gprintf("Realloc of size %d returns memory in MEM1\n", size);
return n;
}
n = MEM2_alloc(size);
if (n == 0) {
gprintf("Realloc of size %d returns memory in MEM2\n", size);
return 0;
}
if (p != 0)
{
memcpy(n, p, __real_malloc_usable_size(p) < size ? __real_malloc_usable_size(p) : size);
__real_free(p);
}
gprintf("Realloc of size %d returns memory in MEM2\n", size);
return n;
}
size_t __wrap_malloc_usable_size(void *p)
{
if (((u32)p & 0x10000000) != 0)
return MEM2_usableSize(p);
return __real_malloc_usable_size(p);
}
}

26
source/memory/mem2.h Normal file
View File

@ -0,0 +1,26 @@
// 2 MEM2 allocators, one for general purpose, one for covers
// Aligned and padded to 32 bytes, as required by many functions
#ifndef __MEM2_HPP
#define __MEM2_HPP
#ifdef __cplusplus
extern "C"
{
#endif
void *MEM2_alloc(unsigned int s);
void *MEM2_realloc(void *p, unsigned int s);
void MEM2_free(void *p);
unsigned int MEM2_usableSize(void *p);
#ifdef __cplusplus
}
void MEM2_init(unsigned int mem2Size);
void MEM2_cleanup(void);
void MEM2_takeBigOnes(bool b);
#endif
#endif // !defined(__MEM2_HPP)

198
source/memory/mem2alloc.cpp Normal file
View File

@ -0,0 +1,198 @@
#include "mem2alloc.h"
#include <ogc/system.h>
#include <algorithm>
#include <string.h>
class LockMutex
{
mutex_t &m_mutex;
public:
LockMutex(mutex_t &m) : m_mutex(m) { LWP_MutexLock(m_mutex); }
~LockMutex(void) { LWP_MutexUnlock(m_mutex); }
};
void CMEM2Alloc::init(unsigned int size)
{
m_baseAddress = (SBlock *)(((u32)SYS_GetArena2Lo() + 31) & ~31);
m_endAddress = (SBlock *)((char *)m_baseAddress + std::min(size * 0x100000, SYS_GetArena2Size() & ~31));
if (m_endAddress > (SBlock *)0x93000000) // See loader/disc.c
m_endAddress = (SBlock *)0x93000000;
SYS_SetArena2Lo(m_endAddress);
LWP_MutexInit(&m_mutex, 0);
}
void CMEM2Alloc::init(void *addr, void *end)
{
m_baseAddress = (SBlock *)(((u32)addr + 31) & ~31);
m_endAddress = (SBlock *)((u32)end & ~31);
LWP_MutexInit(&m_mutex, 0);
}
void CMEM2Alloc::cleanup(void)
{
LWP_MutexDestroy(m_mutex);
m_mutex = 0;
m_first = 0;
// // Try to release the range we took through SYS functions
// if (SYS_GetArena2Lo() == m_endAdress)
// SYS_SetArena2Lo(m_baseAddress);
m_baseAddress = 0;
m_endAddress = 0;
}
void CMEM2Alloc::clear(void)
{
m_first = 0;
memset(m_baseAddress, 0, (u8 *)m_endAddress - (u8 *)m_endAddress);
}
unsigned int CMEM2Alloc::usableSize(void *p)
{
return p == 0 ? 0 : ((SBlock *)p - 1)->s * sizeof (SBlock);
}
void *CMEM2Alloc::allocate(unsigned int s)
{
if (s == 0)
s = 1;
//
LockMutex lock(m_mutex);
//
s = (s - 1) / sizeof (SBlock) + 1;
// First block
if (m_first == 0)
{
if (m_baseAddress + s + 1 >= m_endAddress)
return 0;
m_first = m_baseAddress;
m_first->next = 0;
m_first->prev = 0;
m_first->s = s;
m_first->f = false;
return (void *)(m_first + 1);
}
// Search for a free block
SBlock *i;
SBlock *j;
for (i = m_first; i != 0; i = i->next)
{
if (i->f && i->s >= s)
break;
j = i;
}
// Create a new block
if (i == 0)
{
i = j + j->s + 1;
if (i + s + 1 >= m_endAddress)
return 0;
j->next = i;
i->prev = j;
i->next = 0;
i->s = s;
i->f = false;
return (void *)(i + 1);
}
// Reuse a free block
i->f = false;
// Split it
if (i->s > s + 1)
{
j = i + s + 1;
j->f = true;
j->s = i->s - s - 1;
i->s = s;
j->next = i->next;
j->prev = i;
i->next = j;
if (j->next != 0)
j->next->prev = j;
}
return (void *)(i + 1);
}
void CMEM2Alloc::release(void *p)
{
if (p == 0)
return;
LockMutex lock(m_mutex);
SBlock *i = (SBlock *)p - 1;
i->f = true;
// Merge with previous block
if (i->prev != 0 && i->prev->f)
{
i = i->prev;
i->s += i->next->s + 1;
i->next = i->next->next;
if (i->next != 0)
i->next->prev = i;
}
// Merge with next block
if (i->next != 0 && i->next->f)
{
i->s += i->next->s + 1;
i->next = i->next->next;
if (i->next != 0)
i->next->prev = i;
}
}
void *CMEM2Alloc::reallocate(void *p, unsigned int s)
{
SBlock *i;
SBlock *j;
void *n;
if (s == 0)
s = 1;
if (p == 0)
return allocate(s);
i = (SBlock *)p - 1;
s = (s - 1) / sizeof (SBlock) + 1;
{
LockMutex lock(m_mutex);
// Last block
if (i->next == 0 && i + s + 1 < m_endAddress)
{
i->s = s;
return p;
}
// Size <= current size + next block
if (i->s < s && i->next->f && i->s + i->next->s + 1 >= s)
{
// Merge
i->s += i->next->s + 1;
i->next = i->next->next;
if (i->next != 0)
i->next->prev = i;
}
// Size <= current size
if (i->s >= s)
{
// Split
if (i->s > s + 1)
{
j = i + s + 1;
j->f = true;
j->s = i->s - s - 1;
i->s = s;
j->next = i->next;
j->prev = i;
i->next = j;
if (j->next != 0)
j->next->prev = j;
}
return p;
}
}
// Size > current size
n = allocate(s * sizeof (SBlock));
if (n == 0)
return 0;
memcpy(n, p, i->s * sizeof (SBlock));
release(p);
return n;
}

41
source/memory/mem2alloc.h Normal file
View File

@ -0,0 +1,41 @@
// MEM2 allocator
// Made as a class so i can have 2 sections, one being dedicated to the covers
#ifndef __MEM2ALLOC_HPP
#define __MEM2ALLOC_HPP
#include <ogc/mutex.h>
class CMEM2Alloc
{
public:
void *allocate(unsigned int s);
void release(void *p);
void *reallocate(void *p, unsigned int s);
void init(unsigned int size);
void init(void *addr, void *end);
void cleanup(void);
void clear(void);
static unsigned int usableSize(void *p);
void forceEndAddress(void *newAddr) { m_endAddress = (SBlock *)newAddr; }
void *getEndAddress(void) const { return m_endAddress; }
void info(void *&address, unsigned int &size) const { address = m_baseAddress; size = (const char *)m_endAddress - (const char *)m_baseAddress; }
//
CMEM2Alloc(void) : m_baseAddress(0), m_endAddress(0), m_first(0), m_mutex(0) { }
private:
struct SBlock
{
unsigned int s;
SBlock *next;
SBlock *prev;
bool f;
} __attribute__((aligned(32)));
SBlock *m_baseAddress;
SBlock *m_endAddress;
SBlock *m_first;
mutex_t m_mutex;
private:
CMEM2Alloc(const CMEM2Alloc &);
};
#endif // !defined(__MEM2ALLOC_HPP)

View File

@ -30,6 +30,7 @@
#include "sys.h" #include "sys.h"
#include "wpad.h" #include "wpad.h"
#include "settings/newtitles.h" #include "settings/newtitles.h"
#include "patches/fst.h"
/*** Variables that are also used extern ***/ /*** Variables that are also used extern ***/
GuiWindow * mainWindow = NULL; GuiWindow * mainWindow = NULL;
@ -275,14 +276,14 @@ int MainMenu(int menu) {
if (strcmp(headlessID,"")==0) if (strcmp(headlessID,"")==0)
ResumeGui(); ResumeGui();
bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, Settings.volume); bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, Settings.volume);
bgMusic->SetLoop(1); //loop music bgMusic->SetLoop(1); //loop music
// startup music // startup music
if (strcmp("", Settings.oggload_path) && strcmp("notset", Settings.ogg_path)) { if (strcmp("", Settings.oggload_path) && strcmp("notset", Settings.ogg_path)) {
bgMusic->Load(Settings.ogg_path); bgMusic->Load(Settings.ogg_path);
} }
bgMusic->Play(); bgMusic->Play();
while (currentMenu != MENU_EXIT) { while (currentMenu != MENU_EXIT) {
bgMusic->SetVolume(Settings.volume); bgMusic->SetVolume(Settings.volume);
@ -490,13 +491,17 @@ int MainMenu(int menu) {
if(dvdheader) if(dvdheader)
delete dvdheader; delete dvdheader;
gprintf("Loading BCA data...");
ret = do_bca_code(header->id);
gprintf("%d\n", ret);
if (reloadblock == on && Sys_IsHermes()) { if (reloadblock == on && Sys_IsHermes()) {
patch_cios_data(); patch_cios_data();
if (!load_from_fat) { if (!load_from_fat) {
mload_close(); mload_close();
} }
} }
u8 errorfixer002 = 0; u8 errorfixer002 = 0;
switch (fix002) { switch (fix002) {
case on: case on:

View File

@ -16,7 +16,6 @@ extern char headlessID[8];
***************************************************************************/ ***************************************************************************/
int MenuCheck() { int MenuCheck() {
gprintf("\nMenuCheck()"); gprintf("\nMenuCheck()");
//WindowPrompt("test",0,"ok");
int menu = MENU_NONE; int menu = MENU_NONE;
int i = 0; int i = 0;
int choice; int choice;
@ -59,12 +58,12 @@ int MenuCheck() {
extern PartList partitions; extern PartList partitions;
// Added for slow HDD // Added for slow HDD
for (int runs = 0; runs < 10; runs++) { for (int runs = 0; runs < 10; runs++) {
if (Partition_GetList(&partitions) != 0) { if (Partition_GetList(WBFS_DEVICE_USB, &partitions) != 0) {
sleep(1); sleep(1);
continue; continue;
} }
if (Settings.partition != -1 && partitions.num > Settings.partition) { if (Settings.partition != -1 && partitions.num > Settings.partition) {
PartInfo pinfo = partitions.pinfo[Settings.partition]; PartInfo pinfo = partitions.pinfo[Settings.partition];
ret2 = WBFS_OpenPart(pinfo.fs_type == FS_TYPE_FAT32, pinfo.fat_i, partitions.pentry[Settings.partition].sector, partitions.pentry[Settings.partition].size, (char *) &game_partition); ret2 = WBFS_OpenPart(pinfo.fs_type == FS_TYPE_FAT32, pinfo.fat_i, partitions.pentry[Settings.partition].sector, partitions.pentry[Settings.partition].size, (char *) &game_partition);
@ -103,14 +102,14 @@ int MenuCheck() {
} }
} }
} }
if (ret2 >= 0 || load_from_fat) { if (ret2 >= 0 || load_from_fat) {
cfg_save_global(); cfg_save_global();
break; break;
} }
sleep(1); sleep(1);
} }
if (ret2 < 0 && !load_from_fat) { if (ret2 < 0 && !load_from_fat) {
choice = WindowPrompt(tr("No WBFS or FAT game partition found"),tr("You need to select or format a partition"), tr("Select"), tr("Format"), tr("Return")); choice = WindowPrompt(tr("No WBFS or FAT game partition found"),tr("You need to select or format a partition"), tr("Select"), tr("Format"), tr("Return"));
if (choice == 0) { if (choice == 0) {
@ -120,7 +119,7 @@ int MenuCheck() {
menu = MENU_FORMAT; menu = MENU_FORMAT;
} }
} }
ret2 = Disc_Init(); ret2 = Disc_Init();
if (ret2 < 0) { if (ret2 < 0) {
WindowPrompt (tr("Error !"),tr("Could not initialize DIP module!"),tr("OK")); WindowPrompt (tr("Error !"),tr("Could not initialize DIP module!"),tr("OK"));
@ -136,6 +135,13 @@ int MenuCheck() {
sleep(1); sleep(1);
} }
// open database if needed, load titles if needed
OpenXMLDatabase(Settings.titlestxt_path,Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride==1?true:false, true);
// titles.txt loaded after database to override database titles with custom titles
//snprintf(pathname, sizeof(pathname), "%stitles.txt", Settings.titlestxt_path);
//cfg_parsefile(pathname, &title_set);
//Spieleliste laden //Spieleliste laden
__Menu_GetEntries(0); __Menu_GetEntries(0);
@ -151,13 +157,6 @@ int MenuCheck() {
USBDevice_Init(); USBDevice_Init();
SDCard_Init(); SDCard_Init();
} }
// open database if needed, load titles if needed
OpenXMLDatabase(Settings.titlestxt_path,Settings.db_language, Settings.db_JPtoEN, true, Settings.titlesOverride==1?true:false, true);
// titles.txt loaded after database to override database titles with custom titles
//snprintf(pathname, sizeof(pathname), "%stitles.txt", Settings.titlestxt_path);
//cfg_parsefile(pathname, &title_set);
return menu; return menu;
} }

View File

@ -9,6 +9,7 @@
#include "prompts/DiscBrowser.h" #include "prompts/DiscBrowser.h"
#include "settings/Settings.h" #include "settings/Settings.h"
#include "wpad.h" #include "wpad.h"
#include "sys.h"
#include "libwiigui/gui_gamebrowser.h" #include "libwiigui/gui_gamebrowser.h"
#include "libwiigui/gui_gamegrid.h" #include "libwiigui/gui_gamegrid.h"
@ -574,6 +575,8 @@ int MenuDiscList() {
} }
ResumeGui(); ResumeGui();
// ShowMemInfo();
while (menu == MENU_NONE) { while (menu == MENU_NONE) {

View File

@ -1,117 +1,122 @@
#define size_dip_plugin 3080 #define size_dip_plugin 3224
unsigned char dip_plugin[3080] __attribute__((aligned (32)))={ unsigned char dip_plugin[3224] __attribute__((aligned (32)))={
19, 119, 228, 85, 18, 52, 0, 1, 32, 34, 205, 172, 32, 32, 13, 57, 32, 32, 8, 197, 32, 32, 8, 153, 32, 32, 91, 129, 32, 19, 119, 228, 85, 18, 52, 0, 1, 32, 34, 205, 172, 32, 32, 13, 57, 32, 32, 8, 197, 32, 32, 8, 153, 32, 32, 91, 129, 32,
32, 0, 73, 32, 32, 40, 117, 32, 32, 54, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 73, 32, 32, 40, 117, 32, 32, 54, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 119, 233,
19, 119, 233, 53, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 71, 120, 234, 0, 2, 7, 70, 192, 71, 160, 19, 119, 233, 117, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 71, 120, 234, 0, 2, 23, 70, 192,
120, 234, 0, 2, 23, 70, 192, 71, 120, 234, 0, 2, 39, 70, 192, 71, 120, 234, 0, 2, 31, 70, 192, 71, 120, 234, 0, 2, 5, 71, 120, 234, 0, 2, 39, 70, 192, 71, 120, 234, 0, 2, 55, 70, 192, 71, 120, 234, 0, 2, 47, 70, 192, 71, 120, 234, 0,
70, 192, 71, 120, 234, 0, 1, 247, 70, 192, 71, 120, 234, 0, 2, 29, 70, 192, 71, 120, 234, 0, 2, 25, 70, 192, 71, 120, 2, 21, 70, 192, 71, 120, 234, 0, 2, 7, 70, 192, 71, 120, 234, 0, 2, 45, 70, 192, 71, 120, 234, 0, 2, 41, 70, 192, 71,
234, 0, 2, 33, 181, 0, 75, 7, 176, 137, 147, 0, 70, 104, 35, 0, 33, 0, 34, 0, 147, 1, 147, 2, 240, 0, 252, 85, 176, 120, 234, 0, 2, 49, 181, 0, 75, 7, 176, 137, 147, 0, 70, 104, 35, 0, 33, 0, 34, 0, 147, 1, 147, 2, 240, 0, 252, 157,
9, 188, 2, 71, 8, 70, 192, 227, 0, 0, 0, 181, 16, 28, 3, 34, 32, 28, 12, 72, 13, 28, 25, 247, 255, 255, 210, 33, 32, 176, 9, 188, 2, 71, 8, 70, 192, 227, 0, 0, 0, 181, 16, 28, 3, 34, 32, 28, 12, 72, 13, 28, 25, 247, 255, 255, 210, 33,
72, 11, 247, 255, 255, 202, 73, 10, 34, 1, 104, 11, 66, 19, 209, 253, 34, 32, 28, 32, 73, 6, 247, 255, 255, 196, 28, 32, 72, 11, 247, 255, 255, 202, 73, 10, 34, 1, 104, 11, 66, 19, 209, 253, 34, 32, 28, 32, 73, 6, 247, 255, 255, 196,
32, 33, 32, 247, 255, 255, 188, 75, 4, 104, 24, 188, 16, 188, 2, 71, 8, 70, 192, 13, 0, 96, 0, 13, 0, 96, 28, 13, 0, 28, 32, 33, 32, 247, 255, 255, 188, 75, 4, 104, 24, 188, 16, 188, 2, 71, 8, 70, 192, 13, 0, 96, 0, 13, 0, 96, 28, 13,
96, 32, 181, 240, 70, 95, 70, 86, 70, 77, 70, 68, 180, 240, 10, 203, 70, 154, 75, 20, 176, 137, 37, 0, 28, 7, 28, 14, 0, 96, 32, 181, 240, 70, 95, 70, 86, 70, 77, 70, 68, 180, 240, 10, 203, 70, 154, 75, 20, 176, 137, 37, 0, 28, 7, 28,
70, 145, 70, 108, 70, 155, 70, 168, 70, 91, 96, 35, 70, 67, 96, 99, 96, 163, 70, 83, 96, 227, 28, 56, 70, 75, 28, 49, 14, 70, 145, 70, 108, 70, 155, 70, 168, 70, 91, 96, 35, 70, 67, 96, 99, 96, 163, 70, 83, 96, 227, 28, 56, 70, 75, 28,
97, 35, 247, 255, 255, 162, 70, 104, 28, 57, 28, 50, 240, 0, 252, 6, 53, 1, 40, 0, 209, 8, 176, 9, 188, 60, 70, 144, 49, 97, 35, 247, 255, 255, 162, 70, 104, 28, 57, 28, 50, 240, 0, 252, 78, 53, 1, 40, 0, 209, 8, 176, 9, 188, 60, 70,
70, 153, 70, 162, 70, 171, 188, 240, 188, 2, 71, 8, 45, 15, 217, 223, 231, 243, 208, 0, 0, 0, 181, 112, 176, 136, 75, 144, 70, 153, 70, 162, 70, 171, 188, 240, 188, 2, 71, 8, 45, 15, 217, 223, 231, 243, 208, 0, 0, 0, 181, 112, 176, 136,
8, 28, 6, 28, 13, 70, 108, 147, 0, 96, 97, 146, 2, 247, 255, 255, 129, 28, 49, 28, 42, 70, 104, 240, 0, 251, 229, 176, 75, 8, 28, 6, 28, 13, 70, 108, 147, 0, 96, 97, 146, 2, 247, 255, 255, 129, 28, 49, 28, 42, 70, 104, 240, 0, 252, 45,
8, 188, 112, 188, 2, 71, 8, 168, 0, 0, 0, 181, 240, 70, 95, 70, 86, 70, 77, 70, 68, 180, 240, 176, 143, 144, 4, 145, 176, 8, 188, 112, 188, 2, 71, 8, 168, 0, 0, 0, 181, 240, 70, 95, 70, 86, 70, 77, 70, 68, 180, 240, 176, 143, 144, 4,
3, 146, 2, 41, 0, 209, 0, 224, 126, 10, 82, 70, 145, 35, 128, 34, 0, 1, 27, 70, 147, 34, 255, 147, 1, 3, 210, 171, 6, 145, 3, 146, 2, 41, 0, 209, 0, 224, 126, 10, 82, 70, 145, 35, 128, 34, 0, 1, 27, 70, 147, 34, 255, 147, 1, 3, 210, 171,
146, 0, 70, 152, 224, 7, 154, 3, 68, 179, 69, 90, 217, 62, 154, 5, 24, 179, 10, 219, 68, 153, 154, 3, 70, 91, 26, 214, 6, 146, 0, 70, 152, 224, 7, 154, 3, 68, 179, 69, 90, 217, 62, 154, 5, 24, 179, 10, 219, 68, 153, 154, 3, 70, 91, 26,
70, 74, 2, 83, 154, 2, 66, 154, 216, 87, 35, 0, 147, 5, 36, 0, 159, 4, 34, 128, 68, 95, 28, 56, 28, 49, 1, 18, 240, 214, 70, 74, 2, 83, 154, 2, 66, 154, 216, 87, 35, 0, 147, 5, 36, 0, 159, 4, 34, 128, 68, 95, 28, 56, 28, 49, 1, 18,
0, 248, 103, 44, 0, 209, 47, 40, 0, 208, 45, 155, 0, 28, 6, 66, 152, 217, 1, 38, 255, 3, 246, 10, 242, 70, 146, 36, 240, 0, 248, 103, 44, 0, 209, 47, 40, 0, 208, 45, 155, 0, 28, 6, 66, 152, 217, 1, 38, 255, 3, 246, 10, 242, 70, 146,
0, 75, 43, 70, 66, 96, 19, 35, 0, 96, 83, 96, 147, 70, 83, 96, 211, 70, 75, 97, 19, 28, 56, 28, 49, 247, 255, 255, 38, 36, 0, 75, 43, 70, 66, 96, 19, 35, 0, 96, 83, 96, 147, 70, 83, 96, 211, 70, 75, 97, 19, 28, 56, 28, 49, 247, 255, 255,
70, 64, 28, 57, 28, 50, 240, 0, 251, 138, 52, 1, 28, 5, 40, 0, 208, 192, 44, 15, 217, 230, 45, 0, 208, 188, 176, 15, 38, 70, 64, 28, 57, 28, 50, 240, 0, 251, 210, 52, 1, 28, 5, 40, 0, 208, 192, 44, 15, 217, 230, 45, 0, 208, 188, 176,
28, 40, 188, 60, 70, 144, 70, 153, 70, 162, 70, 171, 188, 240, 188, 2, 71, 8, 154, 5, 25, 147, 154, 1, 66, 147, 217, 15, 28, 40, 188, 60, 70, 144, 70, 153, 70, 162, 70, 171, 188, 240, 188, 2, 71, 8, 154, 5, 25, 147, 154, 1, 66, 147,
1, 155, 5, 26, 214, 32, 128, 1, 0, 33, 32, 247, 255, 254, 251, 28, 4, 40, 0, 208, 18, 33, 128, 1, 9, 70, 74, 247, 255, 217, 1, 155, 5, 26, 214, 32, 128, 1, 0, 33, 32, 247, 255, 254, 251, 28, 4, 40, 0, 208, 18, 33, 128, 1, 9, 70, 74, 247,
255, 59, 28, 5, 40, 0, 208, 15, 28, 32, 247, 255, 254, 217, 231, 216, 26, 211, 0, 155, 28, 28, 147, 5, 30, 99, 65, 156, 255, 255, 59, 28, 5, 40, 0, 208, 15, 28, 32, 247, 255, 254, 217, 231, 216, 26, 211, 0, 155, 28, 28, 147, 5, 30, 99,
231, 163, 37, 1, 66, 109, 231, 208, 37, 0, 231, 206, 154, 5, 28, 56, 24, 161, 28, 50, 247, 255, 254, 214, 28, 56, 28, 65, 156, 231, 163, 37, 1, 66, 109, 231, 208, 37, 0, 231, 206, 154, 5, 28, 56, 24, 161, 28, 50, 247, 255, 254, 214, 28,
49, 247, 255, 254, 206, 231, 228, 70, 192, 208, 0, 0, 0, 181, 48, 28, 13, 28, 20, 6, 195, 209, 18, 75, 15, 66, 152, 56, 28, 49, 247, 255, 254, 206, 231, 228, 70, 192, 208, 0, 0, 0, 181, 48, 28, 13, 28, 20, 6, 195, 209, 18, 75, 15, 66,
217, 19, 33, 0, 75, 14, 24, 194, 75, 14, 66, 154, 216, 1, 75, 13, 26, 25, 66, 161, 211, 5, 28, 8, 66, 169, 216, 10, 152, 217, 19, 33, 0, 75, 14, 24, 194, 75, 14, 66, 154, 216, 1, 75, 13, 26, 25, 66, 161, 211, 5, 28, 8, 66, 169, 216,
30, 99, 67, 152, 224, 0, 32, 0, 188, 48, 188, 2, 71, 8, 35, 192, 4, 91, 26, 25, 231, 232, 28, 40, 30, 99, 67, 152, 231, 10, 30, 99, 67, 152, 224, 0, 32, 0, 188, 48, 188, 2, 71, 8, 35, 192, 4, 91, 26, 25, 231, 232, 28, 40, 30, 99, 67, 152,
244, 1, 127, 255, 255, 240, 0, 0, 0, 3, 97, 127, 255, 19, 97, 128, 0, 71, 112, 70, 192, 181, 48, 28, 4, 72, 15, 28, 231, 244, 1, 127, 255, 255, 240, 0, 0, 0, 3, 97, 127, 255, 19, 97, 128, 0, 71, 112, 70, 192, 181, 48, 28, 4, 72, 15,
13, 104, 131, 104, 193, 176, 129, 24, 91, 24, 154, 105, 3, 43, 0, 209, 15, 104, 67, 43, 0, 209, 7, 28, 32, 28, 41, 247, 28, 13, 104, 131, 104, 193, 176, 129, 24, 91, 24, 154, 105, 3, 43, 0, 209, 15, 104, 67, 43, 0, 209, 7, 28, 32, 28, 41,
255, 255, 13, 176, 1, 188, 48, 188, 2, 71, 8, 28, 32, 28, 41, 247, 255, 255, 27, 231, 246, 28, 32, 28, 41, 240, 0, 249, 247, 255, 255, 13, 176, 1, 188, 48, 188, 2, 71, 8, 28, 32, 28, 41, 247, 255, 255, 27, 231, 246, 28, 32, 28, 41, 240,
220, 231, 241, 70, 192, 19, 119, 240, 0, 181, 240, 79, 27, 35, 1, 28, 4, 96, 59, 176, 129, 33, 32, 247, 255, 254, 127, 0, 249, 246, 231, 241, 70, 192, 19, 119, 240, 0, 181, 240, 79, 27, 35, 1, 28, 4, 96, 59, 176, 129, 33, 32, 247, 255,
104, 227, 43, 8, 208, 8, 28, 32, 240, 0, 250, 214, 35, 0, 96, 59, 176, 1, 188, 240, 188, 2, 71, 8, 105, 163, 37, 197, 254, 127, 104, 227, 43, 8, 208, 8, 28, 32, 240, 0, 250, 246, 35, 0, 96, 59, 176, 1, 188, 240, 188, 2, 71, 8, 105, 163,
104, 24, 104, 89, 247, 255, 254, 109, 105, 163, 1, 173, 104, 27, 28, 40, 33, 8, 104, 92, 104, 30, 247, 255, 254, 100, 37, 197, 104, 24, 104, 89, 247, 255, 254, 109, 105, 163, 1, 173, 104, 27, 28, 40, 33, 8, 104, 92, 104, 30, 247, 255,
75, 10, 4, 36, 64, 30, 67, 52, 78, 9, 96, 44, 28, 40, 33, 4, 96, 52, 247, 255, 254, 73, 28, 48, 33, 4, 247, 255, 254, 254, 100, 75, 10, 4, 36, 64, 30, 67, 52, 78, 9, 96, 44, 28, 40, 33, 4, 96, 52, 247, 255, 254, 73, 28, 48, 33, 4, 247,
69, 35, 0, 96, 59, 32, 0, 231, 217, 70, 192, 19, 119, 240, 40, 0, 0, 255, 255, 0, 0, 49, 136, 181, 16, 73, 20, 28, 4, 255, 254, 69, 35, 0, 96, 59, 32, 0, 231, 217, 70, 192, 19, 119, 240, 40, 0, 0, 255, 255, 0, 0, 49, 136, 181, 16, 73,
104, 139, 104, 202, 24, 154, 105, 11, 43, 0, 209, 18, 104, 75, 43, 0, 209, 11, 33, 32, 247, 255, 254, 175, 40, 0, 219, 20, 28, 4, 104, 139, 104, 202, 24, 154, 105, 11, 43, 0, 209, 18, 104, 75, 43, 0, 209, 11, 33, 32, 247, 255, 254, 175,
3, 105, 162, 75, 12, 66, 154, 208, 10, 188, 16, 188, 2, 71, 8, 33, 32, 247, 255, 254, 185, 231, 242, 33, 32, 240, 0, 40, 0, 219, 3, 105, 162, 75, 12, 66, 154, 208, 10, 188, 16, 188, 2, 71, 8, 33, 32, 247, 255, 254, 185, 231, 242, 33,
249, 123, 231, 238, 75, 6, 34, 1, 112, 26, 120, 91, 43, 0, 209, 238, 247, 255, 254, 10, 231, 235, 70, 192, 19, 119, 32, 240, 0, 249, 149, 231, 238, 75, 6, 34, 1, 112, 26, 120, 91, 43, 0, 209, 238, 247, 255, 254, 10, 231, 235, 70, 192,
240, 0, 93, 28, 158, 163, 32, 34, 205, 172, 181, 240, 70, 87, 70, 70, 180, 192, 28, 4, 120, 0, 176, 129, 28, 14, 28, 19, 119, 240, 0, 93, 28, 158, 163, 32, 34, 205, 172, 181, 240, 70, 87, 70, 70, 180, 192, 28, 6, 120, 0, 176, 129, 28,
23, 40, 224, 208, 24, 77, 133, 35, 0, 98, 43, 28, 3, 59, 112, 43, 143, 217, 13, 28, 32, 28, 49, 28, 58, 240, 0, 250, 15, 70, 144, 40, 224, 208, 24, 77, 145, 35, 0, 98, 43, 28, 3, 59, 112, 43, 143, 217, 13, 28, 48, 28, 57, 70, 66, 240,
108, 28, 4, 176, 1, 28, 32, 188, 12, 70, 144, 70, 154, 188, 240, 188, 2, 71, 8, 74, 123, 0, 155, 88, 211, 70, 159, 77, 0, 250, 180, 28, 4, 176, 1, 28, 32, 188, 12, 70, 144, 70, 154, 188, 240, 188, 2, 71, 8, 74, 135, 0, 155, 88, 211, 70,
120, 106, 43, 43, 0, 209, 2, 105, 43, 43, 0, 208, 230, 28, 48, 33, 0, 28, 58, 240, 0, 248, 240, 106, 43, 224, 143, 104, 159, 77, 132, 106, 43, 43, 0, 209, 2, 105, 43, 43, 0, 208, 230, 28, 56, 33, 0, 70, 66, 240, 0, 249, 10, 106, 43, 96,
107, 43, 0, 209, 2, 105, 43, 43, 0, 208, 217, 36, 0, 231, 221, 35, 1, 34, 37, 84, 171, 104, 43, 43, 0, 208, 0, 224, 59, 28, 56, 70, 65, 247, 255, 253, 212, 36, 0, 231, 223, 104, 107, 43, 0, 209, 2, 105, 43, 43, 0, 208, 211, 36, 0, 231,
173, 28, 32, 28, 58, 240, 0, 250, 62, 28, 4, 34, 0, 35, 37, 84, 234, 44, 0, 209, 204, 224, 46, 104, 235, 104, 169, 70, 215, 104, 107, 43, 0, 209, 2, 105, 43, 43, 0, 208, 203, 28, 56, 33, 0, 70, 66, 240, 0, 248, 239, 28, 56, 70, 65, 247,
154, 105, 43, 70, 136, 43, 0, 209, 0, 224, 176, 32, 0, 34, 0, 70, 67, 70, 81, 67, 11, 209, 2, 42, 0, 209, 0, 224, 176, 255, 253, 187, 36, 0, 231, 198, 104, 115, 36, 0, 96, 171, 231, 194, 104, 171, 231, 217, 104, 115, 36, 0, 96, 43, 231,
28, 3, 30, 90, 65, 147, 96, 107, 28, 48, 28, 57, 247, 255, 255, 107, 28, 4, 231, 176, 105, 43, 43, 0, 208, 167, 35, 188, 104, 43, 231, 211, 104, 115, 97, 43, 43, 0, 208, 6, 28, 40, 28, 49, 48, 24, 49, 8, 34, 6, 247, 255, 253, 166, 105,
2, 224, 85, 104, 97, 104, 162, 40, 208, 209, 0, 224, 144, 28, 48, 247, 255, 254, 250, 28, 4, 40, 0, 209, 160, 35, 37, 115, 36, 0, 97, 107, 231, 171, 105, 43, 231, 194, 104, 114, 35, 36, 84, 234, 36, 0, 231, 164, 104, 235, 104, 172, 70,
92, 235, 43, 0, 209, 156, 28, 48, 28, 57, 247, 255, 254, 237, 231, 151, 35, 36, 92, 234, 42, 0, 209, 179, 105, 41, 84, 154, 105, 43, 43, 0, 209, 0, 224, 170, 32, 0, 34, 0, 70, 83, 67, 35, 209, 2, 42, 0, 209, 0, 224, 142, 28, 3, 30, 90,
234, 35, 37, 96, 42, 96, 106, 96, 170, 96, 234, 98, 42, 84, 234, 70, 136, 41, 0, 209, 0, 231, 128, 105, 108, 247, 255, 65, 147, 96, 107, 28, 56, 70, 65, 247, 255, 255, 70, 28, 4, 231, 139, 35, 1, 34, 37, 84, 171, 104, 43, 43, 0, 209, 0,
253, 142, 70, 64, 28, 41, 28, 34, 56, 1, 49, 24, 240, 0, 248, 249, 28, 4, 231, 122, 104, 107, 43, 0, 208, 93, 75, 60, 224, 132, 104, 113, 104, 178, 28, 56, 247, 255, 254, 214, 28, 4, 34, 0, 35, 37, 84, 234, 44, 0, 208, 0, 231, 120, 28,
36, 160, 98, 43, 2, 36, 231, 114, 104, 107, 43, 0, 209, 3, 105, 43, 43, 0, 209, 0, 231, 101, 104, 99, 104, 162, 7, 155, 56, 70, 65, 247, 255, 254, 201, 231, 115, 104, 115, 72, 70, 64, 24, 247, 255, 253, 139, 28, 4, 231, 108, 76, 68, 33,
67, 19, 74, 53, 36, 0, 64, 19, 96, 235, 231, 98, 104, 99, 72, 51, 64, 24, 247, 255, 253, 122, 28, 4, 231, 91, 104, 98, 64, 28, 32, 247, 255, 253, 106, 34, 0, 28, 33, 224, 3, 50, 1, 42, 64, 209, 0, 231, 90, 92, 163, 43, 0, 208, 248, 34,
35, 36, 84, 234, 36, 0, 231, 86, 105, 43, 96, 51, 28, 48, 28, 57, 247, 255, 253, 67, 36, 0, 231, 78, 104, 99, 97, 43, 64, 28, 56, 247, 255, 253, 80, 28, 56, 33, 64, 247, 255, 253, 72, 36, 0, 231, 83, 35, 36, 92, 234, 42, 0, 208, 0, 231,
43, 0, 209, 40, 105, 99, 36, 0, 97, 107, 231, 70, 104, 43, 231, 238, 104, 99, 36, 0, 96, 43, 231, 64, 104, 171, 231, 116, 84, 234, 35, 37, 84, 234, 105, 43, 96, 42, 96, 106, 96, 170, 96, 234, 98, 42, 70, 154, 43, 0, 209, 0, 231, 59,
232, 104, 99, 36, 0, 96, 171, 231, 58, 104, 107, 43, 0, 209, 3, 105, 43, 43, 0, 209, 0, 231, 45, 28, 48, 33, 0, 28, 105, 108, 247, 255, 253, 73, 70, 80, 28, 41, 28, 34, 56, 1, 49, 24, 240, 0, 248, 206, 28, 4, 231, 53, 104, 113, 104,
58, 240, 0, 248, 55, 28, 48, 28, 57, 247, 255, 253, 29, 36, 0, 231, 40, 104, 97, 104, 162, 28, 48, 247, 255, 254, 122, 178, 40, 208, 208, 59, 28, 56, 247, 255, 254, 133, 28, 4, 40, 0, 208, 0, 231, 42, 35, 37, 92, 235, 43, 0, 208, 0, 231,
28, 4, 231, 79, 28, 40, 28, 33, 49, 8, 34, 6, 48, 24, 247, 255, 253, 17, 231, 206, 105, 43, 43, 0, 209, 158, 231, 15, 37, 231, 171, 105, 43, 43, 0, 209, 0, 231, 26, 35, 2, 231, 55, 104, 107, 43, 0, 209, 3, 105, 43, 43, 0, 209, 0, 231,
2, 201, 2, 82, 231, 107, 28, 58, 28, 32, 28, 49, 240, 0, 249, 121, 28, 2, 30, 83, 65, 154, 231, 71, 105, 43, 43, 0, 17, 104, 115, 104, 178, 7, 155, 67, 19, 74, 24, 36, 0, 64, 19, 96, 235, 231, 14, 104, 107, 43, 0, 208, 17, 75, 21, 36,
208, 0, 231, 74, 96, 106, 36, 0, 231, 2, 70, 192, 19, 119, 240, 0, 19, 119, 233, 144, 0, 5, 49, 0, 255, 255, 128, 0, 160, 98, 43, 2, 36, 231, 6, 105, 43, 43, 0, 208, 0, 231, 108, 96, 106, 36, 0, 230, 255, 28, 48, 70, 66, 240, 0, 249,
127, 255, 255, 255, 181, 240, 70, 87, 70, 78, 70, 69, 180, 224, 70, 128, 28, 14, 70, 148, 42, 0, 208, 51, 33, 3, 28, 175, 28, 4, 231, 122, 105, 43, 43, 0, 209, 234, 230, 239, 2, 201, 2, 82, 231, 192, 70, 66, 28, 48, 240, 0, 249, 162,
2, 64, 10, 35, 4, 26, 155, 28, 24, 64, 8, 69, 96, 216, 49, 40, 0, 208, 49, 36, 0, 70, 67, 85, 30, 52, 1, 66, 160, 216, 28, 2, 30, 83, 65, 154, 231, 78, 70, 192, 19, 119, 240, 0, 19, 119, 234, 32, 127, 255, 255, 255, 19, 119, 233, 160,
250, 69, 132, 208, 32, 70, 99, 26, 27, 8, 159, 70, 153, 0, 187, 70, 154, 43, 0, 208, 17, 4, 51, 6, 50, 2, 49, 67, 26, 255, 255, 128, 0, 0, 5, 49, 0, 181, 240, 70, 87, 70, 78, 70, 69, 180, 224, 70, 128, 28, 14, 70, 148, 42, 0, 208, 51,
67, 10, 28, 21, 70, 67, 67, 53, 24, 26, 33, 0, 0, 139, 49, 1, 80, 213, 66, 185, 211, 250, 68, 84, 69, 209, 208, 6, 70, 33, 3, 28, 2, 64, 10, 35, 4, 26, 155, 28, 24, 64, 8, 69, 96, 216, 49, 40, 0, 208, 49, 36, 0, 70, 67, 85, 30, 52, 1,
67, 25, 24, 52, 1, 112, 6, 48, 1, 69, 164, 216, 250, 188, 28, 70, 144, 70, 153, 70, 162, 188, 240, 188, 1, 71, 0, 70, 66, 160, 216, 250, 69, 132, 208, 32, 70, 99, 26, 27, 8, 159, 70, 153, 0, 187, 70, 154, 43, 0, 208, 17, 4, 51, 6, 50,
96, 231, 203, 36, 0, 231, 211, 70, 192, 181, 112, 76, 17, 28, 6, 104, 32, 176, 130, 28, 13, 98, 2, 97, 6, 100, 1, 97, 2, 49, 67, 26, 67, 10, 28, 21, 70, 67, 67, 53, 24, 26, 33, 0, 0, 139, 49, 1, 80, 213, 66, 185, 211, 250, 68, 84, 69,
65, 33, 68, 247, 255, 252, 147, 28, 48, 28, 41, 247, 255, 252, 143, 75, 10, 34, 2, 104, 24, 104, 35, 73, 9, 147, 0, 209, 208, 6, 70, 67, 25, 24, 52, 1, 112, 6, 48, 1, 69, 164, 216, 250, 188, 28, 70, 144, 70, 153, 70, 162, 188, 240,
35, 1, 247, 255, 252, 154, 28, 41, 28, 4, 28, 48, 247, 255, 252, 145, 176, 2, 28, 32, 188, 112, 188, 2, 71, 8, 19, 119, 188, 1, 71, 0, 70, 96, 231, 203, 36, 0, 231, 211, 70, 192, 181, 112, 76, 17, 28, 6, 104, 32, 176, 130, 28, 13, 98, 2,
240, 44, 19, 119, 240, 48, 87, 70, 83, 2, 181, 240, 176, 133, 28, 4, 28, 15, 146, 3, 40, 2, 216, 75, 77, 47, 104, 43, 97, 6, 100, 1, 97, 65, 33, 68, 247, 255, 252, 121, 28, 48, 28, 41, 247, 255, 252, 117, 75, 10, 34, 2, 104, 24, 104,
43, 0, 208, 74, 78, 46, 104, 48, 40, 0, 219, 1, 247, 255, 252, 97, 74, 44, 0, 163, 88, 152, 33, 1, 247, 255, 252, 107, 35, 73, 9, 147, 0, 35, 1, 247, 255, 252, 128, 28, 41, 28, 4, 28, 48, 247, 255, 252, 119, 176, 2, 28, 32, 188, 112, 188,
96, 48, 40, 0, 219, 66, 104, 48, 40, 0, 219, 49, 104, 40, 28, 57, 34, 6, 48, 32, 247, 255, 252, 87, 104, 40, 169, 3, 2, 71, 8, 19, 119, 240, 44, 19, 119, 240, 48, 87, 70, 83, 2, 181, 240, 176, 133, 28, 4, 28, 15, 146, 3, 40, 2, 216,
34, 4, 48, 64, 247, 255, 252, 81, 104, 42, 36, 4, 28, 19, 51, 32, 96, 19, 104, 42, 35, 6, 96, 83, 104, 42, 33, 68, 28, 75, 77, 47, 104, 43, 43, 0, 208, 74, 78, 46, 104, 48, 40, 0, 219, 1, 247, 255, 252, 71, 74, 44, 0, 163, 88, 152, 33,
19, 51, 64, 96, 147, 104, 43, 96, 220, 104, 40, 247, 255, 252, 59, 104, 43, 104, 48, 34, 2, 147, 0, 73, 22, 35, 0, 247, 1, 247, 255, 252, 81, 96, 48, 40, 0, 219, 66, 104, 48, 40, 0, 219, 49, 104, 40, 28, 57, 34, 6, 48, 32, 247, 255, 252,
255, 252, 71, 104, 42, 28, 19, 51, 32, 96, 19, 104, 43, 96, 92, 104, 42, 28, 19, 51, 64, 96, 147, 104, 43, 96, 220, 61, 104, 40, 169, 3, 34, 4, 48, 64, 247, 255, 252, 55, 104, 42, 36, 4, 28, 19, 51, 32, 96, 19, 104, 42, 35, 6, 96, 83,
176, 5, 188, 240, 188, 2, 71, 8, 32, 1, 66, 64, 231, 248, 75, 11, 78, 8, 96, 43, 35, 1, 66, 91, 96, 51, 231, 179, 44, 104, 42, 33, 68, 28, 19, 51, 64, 96, 147, 104, 43, 96, 220, 104, 40, 247, 255, 252, 33, 104, 43, 104, 48, 34, 2, 147,
0, 209, 186, 72, 8, 33, 1, 247, 255, 252, 31, 96, 48, 231, 180, 70, 192, 19, 119, 240, 44, 19, 119, 240, 48, 19, 119, 0, 73, 22, 35, 0, 247, 255, 252, 45, 104, 42, 28, 19, 51, 32, 96, 19, 104, 43, 96, 92, 104, 42, 28, 19, 51, 64, 96,
235, 252, 87, 70, 83, 1, 19, 119, 240, 64, 19, 119, 235, 208, 233, 45, 64, 128, 229, 159, 113, 0, 229, 151, 112, 0, 147, 104, 43, 96, 220, 176, 5, 188, 240, 188, 2, 71, 8, 32, 1, 66, 64, 231, 248, 75, 11, 78, 8, 96, 43, 35, 1, 66, 91,
235, 0, 0, 45, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 236, 229, 151, 112, 0, 235, 0, 96, 51, 231, 179, 44, 0, 209, 186, 72, 8, 33, 1, 247, 255, 252, 5, 96, 48, 231, 180, 70, 192, 19, 119, 240, 44, 19,
0, 39, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 216, 229, 151, 112, 0, 235, 0, 0, 33, 232, 119, 240, 48, 19, 119, 236, 140, 87, 70, 83, 1, 19, 119, 240, 64, 19, 119, 236, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 196, 229, 151, 112, 0, 235, 0, 0, 27, 232, 189, 64, 0, 233, 45, 64, 128, 229, 159, 113, 80, 229, 151, 112, 0, 235, 0, 0, 45, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45,
128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 176, 229, 151, 112, 0, 235, 0, 0, 21, 232, 189, 64, 128, 225, 64, 128, 229, 159, 113, 60, 229, 151, 112, 0, 235, 0, 0, 39, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128,
47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 156, 229, 151, 112, 0, 235, 0, 0, 15, 232, 189, 64, 128, 225, 47, 255, 229, 159, 113, 40, 229, 151, 112, 0, 235, 0, 0, 33, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159,
30, 230, 0, 8, 16, 225, 47, 255, 30, 230, 0, 7, 240, 225, 47, 255, 30, 230, 0, 3, 144, 225, 47, 255, 30, 230, 0, 3, 113, 20, 229, 151, 112, 0, 235, 0, 0, 27, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 113, 0, 229,
176, 225, 47, 255, 30, 230, 0, 3, 208, 225, 47, 255, 30, 230, 0, 3, 240, 225, 47, 255, 30, 230, 0, 4, 80, 225, 47, 255, 151, 112, 0, 235, 0, 0, 21, 232, 189, 64, 128, 225, 47, 255, 30, 233, 45, 64, 128, 229, 159, 112, 236, 229, 151, 112,
30, 225, 47, 255, 23, 239, 0, 0, 204, 225, 47, 255, 30, 180, 124, 181, 0, 247, 255, 253, 30, 188, 2, 188, 124, 71, 8, 0, 235, 0, 0, 15, 232, 189, 64, 128, 225, 47, 255, 30, 230, 0, 8, 16, 225, 47, 255, 30, 230, 0, 7, 240, 225, 47, 255,
181, 112, 176, 136, 104, 133, 28, 1, 75, 14, 71, 24, 70, 192, 70, 114, 28, 1, 32, 4, 223, 171, 71, 16, 181, 240, 70, 30, 230, 0, 3, 144, 225, 47, 255, 30, 230, 0, 3, 176, 225, 47, 255, 30, 230, 0, 3, 208, 225, 47, 255, 30, 230, 0, 3,
95, 70, 86, 70, 77, 70, 68, 180, 240, 75, 8, 104, 27, 71, 24, 19, 119, 224, 16, 19, 119, 224, 20, 19, 119, 224, 24, 240, 225, 47, 255, 30, 230, 0, 4, 80, 225, 47, 255, 30, 225, 47, 255, 23, 239, 0, 0, 204, 225, 47, 255, 30, 180, 124,
19, 119, 224, 28, 19, 119, 224, 32, 19, 119, 224, 36, 32, 16, 0, 213, 19, 119, 224, 12, 70, 192, 70, 192, 19, 119, 228, 181, 0, 247, 255, 252, 254, 188, 2, 188, 124, 71, 8, 181, 112, 176, 136, 104, 133, 28, 1, 75, 34, 71, 24, 70, 192, 70,
236, 19, 119, 228, 200, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 70, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 190, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 114, 28, 1, 32, 4, 223, 171, 71, 16, 181, 240, 70, 95, 70, 86, 70, 77, 70, 68, 180, 240,
75, 8, 104, 27, 71, 24, 19, 119, 224, 16, 19, 119, 224, 20, 19, 119, 224, 24, 19, 119, 224, 28, 19, 119, 224, 32, 19,
119, 224, 36, 32, 16, 0, 213, 19, 119, 224, 12, 70, 192, 70, 192, 19, 119, 229, 58, 19, 119, 229, 108, 19, 119, 228,
120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120,
19, 119, 228, 202, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19,
119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 34, 19, 119, 228, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230, 58, 19, 119, 228, 120, 19, 119, 229, 220, 19, 119, 228,
120, 19, 119, 229, 84, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 44, 19, 119, 228, 120, 19, 119, 228, 120, 120, 19, 119, 228, 120, 19, 119, 230, 24, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120,
19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19,
119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230,
120, 19, 119, 228, 120, 19, 119, 229, 142, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 44, 102, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230, 24, 19, 119, 228, 120, 19, 119, 228, 120,
19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 184, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 19, 119, 228, 196, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19,
119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228,
120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120,
19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19,
119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 229, 44, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 230, 24, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228,
120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 158, 19, 119, 228, 120, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230, 70, 19, 119, 229, 170, 19, 119, 228, 120, 19, 119, 228, 120,
19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 158, 19, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 158, 19, 119, 228, 120, 19, 119, 228, 120, 19,
119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230, 14, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 228, 120, 19, 119, 228, 212, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228,
120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 230, 6, 19, 119, 230, 2, 19, 119, 229, 250, 19, 119, 229, 246, 19, 120, 19, 119, 228, 246, 19, 119, 228, 254, 19, 119, 229, 2, 19, 119, 229, 10, 19, 119, 229, 14, 19, 119, 229, 44, 19,
119, 229, 230, 19, 119, 229, 214, 19, 119, 229, 204, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 119, 229, 48, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119,
228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 190, 47, 100, 101, 228, 120, 19, 119, 228, 120, 19, 119, 228, 120, 19, 119, 229, 156, 47, 100, 101, 118, 47, 117, 115, 98, 47, 101, 104,
118, 47, 117, 115, 98, 47, 101, 104, 99, 0, 0, 0, 0, 47, 100, 101, 118, 47, 117, 115, 98, 50, 0, 0, 0, 47, 100, 101, 99, 0, 0, 0, 0, 47, 100, 101, 118, 47, 117, 115, 98, 50, 0, 0, 0, 47, 100, 101, 118, 47, 115, 100, 105, 111, 47, 115,
118, 47, 115, 100, 105, 111, 47, 115, 100, 104, 99, 0, 0, 19, 119, 235, 224, 19, 119, 235, 236, 19, 119, 235, 208 100, 104, 99, 0, 0, 19, 119, 236, 112, 19, 119, 236, 124, 19, 119, 236, 96
}; };

View File

@ -1,3 +1,3 @@
#define size_dip_plugin 3080 #define size_dip_plugin 3224
extern unsigned char dip_plugin[3080]; extern unsigned char dip_plugin[3224];

View File

@ -612,7 +612,6 @@ return 0;
int patch_cios_data() { int patch_cios_data() {
patch_datas[0]=*((u32 *) (dip_plugin+16*4)); patch_datas[0]=*((u32 *) (dip_plugin+16*4));
mload_set_ES_ioctlv_vector((void *) patch_datas[0]); mload_set_ES_ioctlv_vector((void *) patch_datas[0]);
return 1; return 1;

View File

@ -34,6 +34,9 @@
#include "dvd_broadway.h" #include "dvd_broadway.h"
#include "wpad.h" #include "wpad.h"
#include "fatmounter.h" #include "fatmounter.h"
#include "sys.h"
#include "mload/mload.h"
#include "mload/dip_plugin.h"
extern struct SSettings Settings; extern struct SSettings Settings;
@ -95,4 +98,61 @@ u32 do_sd_code(char *filename)
return 1; return 1;
} }
u32 do_bca_code(u8 *gameid)
{
if (IOS_GetVersion() == 222 || IOS_GetVersion() == 223)
{
FILE *fp;
u32 filesize;
char filepath[150];
memset(filepath, 0, 150);
u8 bcaCode[64] ATTRIBUTE_ALIGN(32);
sprintf(filepath, "%s%6s", Settings.BcaCodepath, gameid);
filepath[strlen(Settings.BcaCodepath)+6] = '.';
filepath[strlen(Settings.BcaCodepath)+7] = 'b';
filepath[strlen(Settings.BcaCodepath)+8] = 'c';
filepath[strlen(Settings.BcaCodepath)+9] = 'a';
fp = fopen(filepath, "rb");
if (!fp) {
memset(filepath, 0, 150);
sprintf(filepath, "%s%3s", Settings.BcaCodepath, gameid + 1);
filepath[strlen(Settings.BcaCodepath)+3] = '.';
filepath[strlen(Settings.BcaCodepath)+4] = 'b';
filepath[strlen(Settings.BcaCodepath)+5] = 'c';
filepath[strlen(Settings.BcaCodepath)+6] = 'a';
fp = fopen(filepath, "rb");
if (!fp) {
// Set default bcaCode
memset(bcaCode, 0, 64);
bcaCode[0x33] = 1;
}
}
if (fp) {
u32 ret = 0;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
if (filesize == 64) {
fseek(fp, 0, SEEK_SET);
ret = fread(bcaCode, 1, 64, fp);
}
fclose(fp);
if (ret != 64) {
// Set default bcaCode
memset(bcaCode, 0, 64);
bcaCode[0x33] = 1;
}
}
mload_seek(*((u32 *) (dip_plugin+15*4)), SEEK_SET); // offset 15 (bca_data area)
mload_write(bcaCode, 64);
mload_close();
}
return 0;
}

View File

@ -31,6 +31,7 @@ extern "C"
//u32 do_fst(u32 fstlocation); //u32 do_fst(u32 fstlocation);
u32 do_sd_code(char *filename); u32 do_sd_code(char *filename);
u32 do_bca_code(u8 *gameid);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -172,32 +172,6 @@ void dogamehooks(void *addr, u32 len)
} }
break; break;
/*
case 2:
if(memcmp(addr_start, kpadhooks, sizeof(kpadhooks))==0){
patchhook((u32)addr_start, len);
patched = 1;
}
if(memcmp(addr_start, kpadoldhooks, sizeof(kpadoldhooks))==0){
patchhook((u32)addr_start, len);
patched = 1;
}
break;
case 3:
if(memcmp(addr_start, joypadhooks, sizeof(joypadhooks))==0){
patchhook((u32)addr_start, len);
patched = 1;
}
break;
case 4:
if(memcmp(addr_start, recoveryhooks, sizeof(recoveryhooks))==0){
patchhook3((u32)addr_start, len);
}
break;
*/
case 2: case 2:
if(memcmp(addr_start, viwiihooks, sizeof(viwiihooks))==0){ if(memcmp(addr_start, viwiihooks, sizeof(viwiihooks))==0){
@ -206,69 +180,6 @@ void dogamehooks(void *addr, u32 len)
break; break;
/*
case 6:
// jap region free
if(memcmp(addr_start, regionfreehooks, sizeof(regionfreehooks))==0){
regionfreejap((u32)addr_start, len);
}
// usa region free
if(memcmp(addr_start, regionfreehooks, sizeof(regionfreehooks))==0){
regionfreeusa((u32)addr_start, len);
}
// pal region free
if(memcmp(addr_start, regionfreehooks, sizeof(regionfreehooks))==0){
regionfreepal((u32)addr_start, len);
}
// skip disc update
if(memcmp(addr_start, updatecheckhook, sizeof(updatecheckhook))==0){
patchupdatecheck((u32)addr_start, len);
}
break;
case 7:
if(memcmp(addr_start, healthcheckhook, sizeof(healthcheckhook))==0){
removehealthcheck((u32)addr_start, len);
}
break;
// no copy flags
case 8:
// Remove the actual flag so can copy back
if(memcmp(addr_start, nocopyflag5, sizeof(nocopyflag5))==0){
copyflagcheck5((u32)addr_start, len);
}
if(memcmp(addr_start, nocopyflag1, sizeof(nocopyflag1))==0){
copyflagcheck1((u32)addr_start, len);
}
if(memcmp(addr_start, nocopyflag2, sizeof(nocopyflag2))==0){
copyflagcheck2((u32)addr_start, len);
}
// no VC and GH3 save
if(memcmp(addr_start, nocopyflag3, sizeof(nocopyflag2))==0){
copyflagcheck3((u32)addr_start, len);
}
// no VC and GH3 save display remove
if(memcmp(addr_start, nocopyflag4, sizeof(nocopyflag4))==0){
copyflagcheck4((u32)addr_start, len);
}
break;
case 9:
if(memcmp(addr_start, movedvdpatch, sizeof(movedvdpatch))==0){
movedvdhooks((u32)addr_start, len);
}
break;
*/
// multidol // multidol
case 3: case 3:
@ -355,5 +266,3 @@ void vidolpatcher(void *addr, u32 len)
addr_start += 4; addr_start += 4;
} }
} }

View File

@ -181,7 +181,7 @@ void WindowCredits() {
starImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP); starImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
starImg.SetPosition(505,350); starImg.SetPosition(505,350);
int numEntries = 20; int numEntries = 21;
GuiText * txt[numEntries]; GuiText * txt[numEntries];
txt[i] = new GuiText(tr("Credits"), 26, (GXColor) {255, 255, 255, 255}); txt[i] = new GuiText(tr("Credits"), 26, (GXColor) {255, 255, 255, 255});
@ -216,16 +216,16 @@ void WindowCredits() {
i++; i++;
y+=26; y+=26;
txt[i] = new GuiText(" http://code.google.com/p/usbloader-gui/", 20, (GXColor) {255, 255, 255, 255});
txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
txt[i]->SetPosition(50,y);
i++; //y+=28;
txt[i] = new GuiText(tr("Official Site:"), 20, (GXColor) {255, 255, 255, 255}); txt[i] = new GuiText(tr("Official Site:"), 20, (GXColor) {255, 255, 255, 255});
txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(-180,y); txt[i]->SetPosition(10,y);
i++; i++;
y+=28;
txt[i] = new GuiText("http://code.google.com/p/usbloader-gui/", 20, (GXColor) {255, 255, 255, 255});
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(160,y);
i++;
y+=26;
GuiText::SetPresets(22, (GXColor) {255, 255, 255, 255}, 0, GuiText::WRAP,FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); GuiText::SetPresets(22, (GXColor) {255, 255, 255, 255}, 0, GuiText::WRAP,FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP);
@ -244,7 +244,7 @@ void WindowCredits() {
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(160,y); txt[i]->SetPosition(160,y);
i++; i++;
y+=34; y+=26;
char text[100]; char text[100];
@ -257,7 +257,7 @@ void WindowCredits() {
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(160,y); txt[i]->SetPosition(160,y);
i++; i++;
y+=34; y+=26;
txt[i] = new GuiText(tr("Big thanks to:")); txt[i] = new GuiText(tr("Big thanks to:"));
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
@ -290,7 +290,7 @@ void WindowCredits() {
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(160,y); txt[i]->SetPosition(160,y);
i++; i++;
y+=22; y+=26;
txt[i] = new GuiText(tr("Special thanks to:")); txt[i] = new GuiText(tr("Special thanks to:"));
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
@ -326,6 +326,13 @@ void WindowCredits() {
i++; i++;
y+=22; y+=22;
sprintf(text, "Oggzee %s", tr("for FAT support"));
txt[i] = new GuiText(text);
txt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
txt[i]->SetPosition(60,y);
i++;
y+=22;
for (i=0; i < numEntries; i++) for (i=0; i < numEntries; i++)
creditsWindowBox.Append(txt[i]); creditsWindowBox.Append(txt[i]);

View File

@ -46,12 +46,12 @@ static const char *opts_no_yes[settings_off_on_max] = {trNOOP("No"),trNOOP("Yes"
static const char *opts_off_on[settings_off_on_max] = {trNOOP("OFF"),trNOOP("ON") }; static const char *opts_off_on[settings_off_on_max] = {trNOOP("OFF"),trNOOP("ON") };
static const char *opts_videomode[settings_language_max][2] = {{"",trNOOP("Disc Default")},{trNOOP("System Default"),""},{trNOOP("AutoPatch"),""},{trNOOP("Force"), " PAL50"},{trNOOP("Force")," PAL60"},{trNOOP("Force")," NTSC"}}; static const char *opts_videomode[settings_language_max][2] = {{"",trNOOP("Disc Default")},{trNOOP("System Default"),""},{trNOOP("AutoPatch"),""},{trNOOP("Force"), " PAL50"},{trNOOP("Force")," PAL60"},{trNOOP("Force")," NTSC"}};
static const char *opts_language[settings_language_max] = {trNOOP("Console Default"),trNOOP("Japanese"),trNOOP("English"),trNOOP("German"),trNOOP("French"),trNOOP("Spanish"),trNOOP("Italian"),trNOOP("Dutch"),trNOOP("SChinese"),trNOOP("TChinese"),trNOOP("Korean")}; static const char *opts_language[settings_language_max] = {trNOOP("Console Default"),trNOOP("Japanese"),trNOOP("English"),trNOOP("German"),trNOOP("French"),trNOOP("Spanish"),trNOOP("Italian"),trNOOP("Dutch"),trNOOP("SChinese"),trNOOP("TChinese"),trNOOP("Korean")};
static const char *opts_cios[settings_ios_max] = {"IOS 249","IOS 222", "IOS 223"}; static const char *opts_cios[settings_ios_max] = {"IOS 249","IOS 222", "IOS 223", "IOS 250"};
static const char *opts_parentalcontrol[5] = {trNOOP("0 (Everyone)"),trNOOP("1 (Child 7+)"),trNOOP("2 (Teen 12+)"),trNOOP("3 (Mature 16+)"),trNOOP("4 (Adults Only 18+)")}; static const char *opts_parentalcontrol[5] = {trNOOP("0 (Everyone)"),trNOOP("1 (Child 7+)"),trNOOP("2 (Teen 12+)"),trNOOP("3 (Mature 16+)"),trNOOP("4 (Adults Only 18+)")};
static const char *opts_error002[settings_error002_max] = {trNOOP("No"),trNOOP("Yes"),trNOOP("Anti")}; static const char *opts_error002[settings_error002_max] = {trNOOP("No"),trNOOP("Yes"),trNOOP("Anti")};
bool IsValidPartition(int fs_type, int cios) { bool IsValidPartition(int fs_type, int cios) {
if (cios == 249) { if (cios == 249 || cios == 250) {
return fs_type == FS_TYPE_WBFS; return fs_type == FS_TYPE_WBFS;
} else { } else {
return fs_type == FS_TYPE_WBFS || fs_type == FS_TYPE_FAT32; return fs_type == FS_TYPE_WBFS || fs_type == FS_TYPE_FAT32;
@ -992,7 +992,7 @@ int MenuSettings()
if (++Settings.cios >= settings_cios_max) { if (++Settings.cios >= settings_cios_max) {
Settings.cios = 0; Settings.cios = 0;
} }
if (Settings.cios != 0 && ios222rev!=4) { if ((Settings.cios == 1 && ios222rev!=4) || (Settings.cios == 2 && ios223rev != 4)) {
WindowPrompt(tr("Hermes CIOS"),tr("USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!"),tr("OK")); WindowPrompt(tr("Hermes CIOS"),tr("USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!"),tr("OK"));
} }
} }
@ -1022,6 +1022,15 @@ int MenuSettings()
pInfo.fs_type == FS_TYPE_FAT32 ? pInfo.fat_i : pInfo.wbfs_i, pInfo.fs_type == FS_TYPE_FAT32 ? pInfo.fat_i : pInfo.wbfs_i,
partition_size); partition_size);
} }
if (ret == ++Idx || firstRun)
{
if (firstRun) options2.SetName(Idx, "%s", tr("FAT: Use directories"));
if (ret == Idx) {
Settings.FatInstallToDir = Settings.FatInstallToDir == 0 ? 1 : 0;
}
options2.SetValue(Idx, "%s", tr(opts_no_yes[Settings.FatInstallToDir]));
}
if(ret == ++Idx || firstRun) if(ret == ++Idx || firstRun)
{ {
@ -1824,6 +1833,34 @@ int MenuSettings()
options2.SetValue(Idx, "%s", Settings.theme_downloadpath); options2.SetValue(Idx, "%s", Settings.theme_downloadpath);
} }
if(ret == ++Idx || firstRun)
{
if(firstRun) options2.SetName(Idx, "%s", tr("BCA Codes Path"));
if(ret == Idx)
{
w.Remove(&optionBrowser2);
w.Remove(&backBtn);
char entered[100] = "";
strlcpy(entered, Settings.BcaCodepath, sizeof(entered));
titleTxt.SetText(tr("BCA Codes Path"));
int result = BrowseDevice(entered, sizeof(entered), FB_DEFAULT, noFILES);
titleTxt.SetText(tr("Custom Paths"));
w.Append(&optionBrowser2);
w.Append(&backBtn);
if ( result == 1 )
{
int len = (strlen(entered)-1);
if (entered[len] !='/')
strncat (entered, "/", 1);
strlcpy(Settings.BcaCodepath, entered, sizeof(Settings.BcaCodepath));
WindowPrompt(tr("BCA Codes Path changed"),0,tr("OK"));
if (!isInserted(bootDevice))
WindowPrompt(tr("No SD-Card inserted!"),tr("Insert an SD-Card to save."),tr("OK"));
}
}
options2.SetValue(Idx, "%s", Settings.BcaCodepath);
}
firstRun = false; firstRun = false;
} }
} }
@ -2330,8 +2367,12 @@ int GameSettings(struct discHdr * header)
viChoice = Settings.vpatch; viChoice = Settings.vpatch;
if (Settings.cios == ios222) if (Settings.cios == ios222)
iosChoice = i222; iosChoice = i222;
else else if (Settings.cios == 250)
iosChoice = i249; iosChoice = i250;
else if (Settings.cios == ios223)
iosChoice = i223;
else
iosChoice = 249;
parentalcontrolChoice = 0; parentalcontrolChoice = 0;
fix002 = Settings.error002; fix002 = Settings.error002;
countrystrings = Settings.patchcountrystrings; countrystrings = Settings.patchcountrystrings;
@ -2847,6 +2888,10 @@ int GameSettings(struct discHdr * header)
reloadblock = off; reloadblock = off;
if (Settings.cios == ios222) if (Settings.cios == ios222)
iosChoice = i222; iosChoice = i222;
else if (Settings.cios == ios250)
iosChoice = i250;
else if (Settings.cios == ios223)
iosChoice = i223;
else else
iosChoice = i249; iosChoice = i249;
parentalcontrolChoice = 0; parentalcontrolChoice = 0;

View File

@ -201,6 +201,7 @@ void CFG_Default(int widescreen) { // -1 = non forced Mode
snprintf(Settings.homebrewapps_path, sizeof(Settings.homebrewapps_path), "%s/apps/", bootDevice); snprintf(Settings.homebrewapps_path, sizeof(Settings.homebrewapps_path), "%s/apps/", bootDevice);
snprintf(Settings.Cheatcodespath, sizeof(Settings.Cheatcodespath), "%s/codes/", bootDevice); snprintf(Settings.Cheatcodespath, sizeof(Settings.Cheatcodespath), "%s/codes/", bootDevice);
snprintf(Settings.TxtCheatcodespath, sizeof(Settings.TxtCheatcodespath), "%s/txtcodes/", bootDevice); snprintf(Settings.TxtCheatcodespath, sizeof(Settings.TxtCheatcodespath), "%s/txtcodes/", bootDevice);
snprintf(Settings.BcaCodepath, sizeof(Settings.BcaCodepath), "%s/bca/", bootDevice);
snprintf(Settings.dolpath, sizeof(Settings.dolpath), "%s/", bootDevice); snprintf(Settings.dolpath, sizeof(Settings.dolpath), "%s/", bootDevice);
sprintf(Settings.ogg_path, "notset"); sprintf(Settings.ogg_path, "notset");
} }
@ -355,6 +356,7 @@ void Global_Default(void) {
Settings.screensaver = 3; Settings.screensaver = 3;
Settings.partition = -1; Settings.partition = -1;
Settings.marknewtitles = 1; Settings.marknewtitles = 1;
Settings.FatInstallToDir = 0;
} }
@ -532,6 +534,10 @@ void path_set(char *name, char *val) {
strlcpy(Settings.ogg_path, val, sizeof(Settings.ogg_path)); strlcpy(Settings.ogg_path, val, sizeof(Settings.ogg_path));
return; return;
} }
if (strcmp(name, "BcaCodepath") == 0) {
strlcpy(Settings.BcaCodepath, val, sizeof(Settings.BcaCodepath));
return;
}
return; return;
@ -1049,6 +1055,11 @@ void global_cfg_set(char *name, char *val) {
Settings.marknewtitles = i; Settings.marknewtitles = i;
} }
return; return;
} else if (strcmp(name, "fatInstallToDir") == 0) {
int i;
if (sscanf(val, "%d", &i) == 1) {
Settings.FatInstallToDir = i;
}
} }
cfg_bool("godmode", &Settings.godmode); cfg_bool("godmode", &Settings.godmode);
@ -1283,6 +1294,7 @@ bool cfg_save_global() { // save global settings
fprintf(f, "theme_downloadpath = %s\n ", Settings.theme_downloadpath); fprintf(f, "theme_downloadpath = %s\n ", Settings.theme_downloadpath);
fprintf(f, "homebrewapps_path = %s\n ", Settings.homebrewapps_path); fprintf(f, "homebrewapps_path = %s\n ", Settings.homebrewapps_path);
fprintf(f, "Cheatcodespath = %s\n ", Settings.Cheatcodespath); fprintf(f, "Cheatcodespath = %s\n ", Settings.Cheatcodespath);
fprintf(f, "BcaCodepath = %s\n", Settings.BcaCodepath);
fprintf(f, "titlesOverride = %d\n ", Settings.titlesOverride); fprintf(f, "titlesOverride = %d\n ", Settings.titlesOverride);
//fprintf(f, "db_url = %s\n ", Settings.db_url); //fprintf(f, "db_url = %s\n ", Settings.db_url);
//fprintf(f, "db_JPtoEN = %d\n ", Settings.db_JPtoEN); //fprintf(f, "db_JPtoEN = %d\n ", Settings.db_JPtoEN);
@ -1294,6 +1306,7 @@ bool cfg_save_global() { // save global settings
fprintf(f, "discart = %d\n ", Settings.discart); fprintf(f, "discart = %d\n ", Settings.discart);
fprintf(f, "partition = %d\n", Settings.partition); fprintf(f, "partition = %d\n", Settings.partition);
fprintf(f, "marknewtitles = %d\n", Settings.marknewtitles); fprintf(f, "marknewtitles = %d\n", Settings.marknewtitles);
fprintf(f, "fatInstallToDir = %d\n", Settings.FatInstallToDir);
fclose(f); fclose(f);
return true; return true;
} }

View File

@ -298,12 +298,15 @@ extern "C" {
i249=0, i249=0,
i222, i222,
i223, i223,
i250,
settings_ios_max // always the last entry settings_ios_max // always the last entry
}; };
enum { enum {
ios249=0, ios249=0,
ios222, ios222,
ios223,
ios250,
settings_cios_max // always the last entry settings_cios_max // always the last entry
}; };
@ -422,6 +425,8 @@ extern "C" {
u8 discart; u8 discart;
short gamesound; short gamesound;
u8 marknewtitles; u8 marknewtitles;
char BcaCodepath[100];
u8 FatInstallToDir;
}; };
extern struct SSettings Settings; extern struct SSettings Settings;

View File

@ -78,6 +78,35 @@ NewTitles::~NewTitles()
firstTitle = lastTitle = NULL; firstTitle = lastTitle = NULL;
} }
void NewTitles::CheckGame(u8 *titleid)
{
Title *t = firstTitle;
while (t != NULL) {
// Loop all titles, search for the correct titleid
if (strcmp((const char *) titleid, (const char *) t->titleId) == 0) {
return; // Game found, which is excellent
}
t = (Title *) t->next;
}
// Not found, add it
t = new Title();
strncpy((char *) t->titleId, (char *) titleid, 6);
t->timestamp = time(NULL);
if (isNewFile) {
t->timestamp -= (NEW_SECONDS + 1); // Mark all games as not new if this is a new file
}
if (firstTitle == NULL) {
firstTitle = t;
lastTitle = t;
} else {
lastTitle -> next = t;
lastTitle = t;
}
isDirty = true;
}
bool NewTitles::IsNew(u8 *titleid) bool NewTitles::IsNew(u8 *titleid)
{ {
Title *t = firstTitle; Title *t = firstTitle;
@ -95,23 +124,8 @@ bool NewTitles::IsNew(u8 *titleid)
} }
t = (Title *) t->next; t = (Title *) t->next;
} }
// We should never get here, since all files should be added by now!
// Not found, add it CheckGame(titleid);
t = new Title();
strncpy((char *) t->titleId, (char *) titleid, 6);
t->timestamp = time(NULL);
if (isNewFile) {
t->timestamp -= (NEW_SECONDS + 1); // Mark all games as not new if this is a new file
}
if (firstTitle == NULL) {
firstTitle = t;
lastTitle = t;
} else {
lastTitle -> next = t;
lastTitle = t;
}
isDirty = true;
return !isNewFile; // If this is a new file, return false return !isNewFile; // If this is a new file, return false
} }

View File

@ -10,6 +10,7 @@ public:
static void DestroyInstance(); static void DestroyInstance();
void Save(); void Save();
void CheckGame(u8 *titleid);
bool IsNew(u8 *titleid); bool IsNew(u8 *titleid);
void Remove(u8 *titleid); void Remove(u8 *titleid);
private: private:

View File

@ -207,11 +207,22 @@ bool Sys_IsHermes() {
return IOS_GetVersion() == 222 || IOS_GetVersion() == 223; return IOS_GetVersion() == 222 || IOS_GetVersion() == 223;
} }
#include "Prompts/PromptWindows.h"
void ShowMemInfo() {
char buf[255];
struct mallinfo mymallinfo = mallinfo();
sprintf((char *) &buf,"Total: %d, Used: %d, Can be freed: %d", mymallinfo.arena/1024, mymallinfo.uordblks/1024, mymallinfo.keepcost/1024);
WindowPrompt("Mem info", (char *) &buf, "OK");
}
#include "wad/title.h" #include "wad/title.h"
s32 ios222rev = -69; s32 ios222rev = -69;
s32 ios223rev = -69;
s32 ios249rev = -69; s32 ios249rev = -69;
s32 ios250rev = -69;
s32 IOS_ReloadIOSsafe(int ios) s32 IOS_ReloadIOSsafe(int ios)
{ {
@ -219,20 +230,31 @@ s32 IOS_ReloadIOSsafe(int ios)
{ {
if (ios222rev == -69) if (ios222rev == -69)
ios222rev = getIOSrev(0x00000001000000dell); ios222rev = getIOSrev(0x00000001000000dell);
if (ios222rev != 4)return -2; if (ios222rev >= 0 && ios222rev != 4)return -2;
} }
else if (ios==223)
{
if (ios223rev == -69)
ios223rev = getIOSrev(0x00000001000000dfll);
if (ios223rev >= 0 && ios223rev != 4)return -2;
}
else if (ios==249) else if (ios==249)
{ {
if (ios249rev == -69) if (ios249rev == -69)
ios249rev = getIOSrev(0x00000001000000f9ll); ios249rev = getIOSrev(0x00000001000000f9ll);
if (!(ios249rev>=9 && ios249rev<65535))return -2; if (ios249rev >= 0 && !(ios249rev>=9 && ios249rev<65280))return -2;
}
else if (ios==250)
{
if (ios250rev == -69)
ios250rev = getIOSrev(0x00000001000000fall);
if (ios250rev >= 0 && !(ios250rev>=9 && ios250rev<65280))return -2;
} }
return IOS_ReloadIOS(ios); return IOS_ReloadIOS(ios);
} }

View File

@ -16,7 +16,11 @@ int Sys_IosReload(int IOS);
bool Sys_IsHermes(); bool Sys_IsHermes();
s32 IOS_ReloadIOSsafe(int ios); s32 IOS_ReloadIOSsafe(int ios);
void ShowMemInfo();
extern s32 ios222rev; extern s32 ios222rev;
extern s32 ios223rev;
extern s32 ios249rev; extern s32 ios249rev;
extern s32 ios250rev;
#endif #endif

View File

@ -256,6 +256,8 @@ void PretendThereIsADiscInTheDrive(void *buffer, u32 len)
/** Thanks to WiiPower **/ /** Thanks to WiiPower **/
bool NewSuperMarioBrosPatch(void *Address, int Size) bool NewSuperMarioBrosPatch(void *Address, int Size)
{ {
if (IOS_GetVersion() == 222 || IOS_GetVersion() == 223) return false; // Don't use this when using Hermes, it'll use the BCA fix instead...
if (memcmp("SMNE", (char *)0x80000000, 4) == 0) if (memcmp("SMNE", (char *)0x80000000, 4) == 0)
{ {
u8 SearchPattern[32] = { 0x94, 0x21, 0xFF, 0xD0, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x34, 0x39, 0x61, 0x00, 0x30, 0x48, 0x12, 0xD7, 0x89, 0x7C, 0x7B, 0x1B, 0x78, 0x7C, 0x9C, 0x23, 0x78, 0x7C, 0xBD, 0x2B, 0x78 }; u8 SearchPattern[32] = { 0x94, 0x21, 0xFF, 0xD0, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x34, 0x39, 0x61, 0x00, 0x30, 0x48, 0x12, 0xD7, 0x89, 0x7C, 0x7B, 0x1B, 0x78, 0x7C, 0x9C, 0x23, 0x78, 0x7C, 0xBD, 0x2B, 0x78 };
@ -387,7 +389,8 @@ s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8
if (error002fix!=0) { if (error002fix!=0) {
/* ERROR 002 fix (thanks to WiiPower for sharing this)*/ /* ERROR 002 fix (thanks to WiiPower for sharing this)*/
*(u32 *)0x80003140 = *(u32 *)0x80003188; *(u32 *)0x80003188 = *(u32 *)0x80003140;
// *(u32 *)0x80003140 = *(u32 *)0x80003188;
} }
if (cheat || geckoinit) { if (cheat || geckoinit) {

View File

@ -19,8 +19,7 @@ extern "C" {
u8 bufsize; u8 bufsize;
/* Padding */ /* Padding */
u8 isNew; // Use space from the padding below u8 unused1[14];
u8 unused1[13];
/* Magic word */ /* Magic word */
u32 magic; u32 magic;

View File

@ -16,7 +16,6 @@
#include <vector> #include <vector>
#include <wchar.h> #include <wchar.h>
#include "listfiles.h" #include "listfiles.h"
#define typei 0x00010001 #define typei 0x00010001
@ -163,8 +162,8 @@ int __Menu_GetPrevFilter(int t, wchar_t* gameFilter, u32 gameFiltered, wchar_t *
{ {
struct discHdr *header = &buffer[i]; struct discHdr *header = &buffer[i];
/* Is new? */ /* Register game */
header->isNew = NewTitles::Instance()->IsNew(header->id); NewTitles::Instance()->CheckGame(header->id);
/* Filter Favorite */ /* Filter Favorite */
if (Settings.fave && t==0) if (Settings.fave && t==0)
@ -479,8 +478,8 @@ int __Menu_GetGameList(int t, wchar_t* gameFilter, discHdr ** PgameList, u32 *Pg
for (u32 i = 0; i < cnt; i++) { for (u32 i = 0; i < cnt; i++) {
struct discHdr *header = &buffer[i]; struct discHdr *header = &buffer[i];
/* Is new? */ /* Register game */
header->isNew = NewTitles::Instance()->IsNew(header->id); NewTitles::Instance()->CheckGame(header->id);
/* Filters */ /* Filters */
if (Settings.fave && t==0) { if (Settings.fave && t==0) {
@ -515,7 +514,7 @@ int __Menu_GetGameList(int t, wchar_t* gameFilter, discHdr ** PgameList, u32 *Pg
} }
if (!buffer) if (!buffer)
return -1; return -1;
if (Settings.sort==pcount) { if (Settings.sort==pcount) {
qsort(buffer, cnt, sizeof(struct discHdr), __Menu_EntryCmpCount); qsort(buffer, cnt, sizeof(struct discHdr), __Menu_EntryCmpCount);
} else if (Settings.fave) { } else if (Settings.fave) {
@ -547,6 +546,7 @@ int __Menu_GetEntries(int t, const wchar_t* Filter) {
new_gameFilter = wcsdup_new(Filter ? Filter : (gameFilter ? gameFilter : L"") ); new_gameFilter = wcsdup_new(Filter ? Filter : (gameFilter ? gameFilter : L"") );
if(new_gameFilter == NULL) return -1; if(new_gameFilter == NULL) return -1;
for(;;) for(;;)
{ {
if (mountMethod==3) if (mountMethod==3)
@ -562,6 +562,7 @@ int __Menu_GetEntries(int t, const wchar_t* Filter) {
break; break;
new_gameFilter[wcslen(new_gameFilter)-1] = 0; new_gameFilter[wcslen(new_gameFilter)-1] = 0;
} }
/* init GameFilterNextList */ /* init GameFilterNextList */
if(__Menu_GetGameFilter_NextList(new_gameList, new_gameCnt, &new_gameFilter, &new_gameFilterNextList) < 0) if(__Menu_GetGameFilter_NextList(new_gameList, new_gameCnt, &new_gameFilter, &new_gameFilterNextList) < 0)
goto error; goto error;

View File

@ -1,57 +1,123 @@
// Modified by oggzee
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ogcsys.h> #include <ogcsys.h>
#include <unistd.h>
#include "partition_usbloader.h" #include "partition_usbloader.h"
#include "usbstorage.h"
#include "sdhc.h" #include "sdhc.h"
#include "usbstorage.h"
#include "utils.h" #include "utils.h"
#include "libwbfs/libwbfs.h"
#include "wbfs.h" #include "wbfs.h"
#include "libwbfs/libwbfs.h"
/* 'partition table' structure */ /* 'partition table' structure */
typedef struct { typedef struct {
/* Zero bytes */ /* Zero bytes */
u8 padding[446]; u8 padding[446];
/* Partition table entries */ /* Partition table entries */
partitionEntry entries[MAX_PARTITIONS]; partitionEntry entries[MAX_PARTITIONS];
} ATTRIBUTE_PACKED partitionTable; } ATTRIBUTE_PACKED partitionTable;
s32 Partition_GetEntries(partitionEntry *outbuf, u32 *outval) {
static partitionTable table ATTRIBUTE_ALIGN(32);
u32 cnt, sector_size; s32 Partition_GetEntries(u32 device, partitionEntry *outbuf, u32 *outval)
s32 ret; {
static partitionTable table ATTRIBUTE_ALIGN(32);
/* Get sector size */ u32 cnt, sector_size;
ret = USBStorage_GetCapacity(&sector_size); s32 ret;
if (ret < 0)
return ret;
/* Read partition table */ /* Read from specified device */
ret = USBStorage_ReadSectors(0, 1, &table); switch (device) {
if (ret < 0) case WBFS_DEVICE_USB: {
return ret; /* Get sector size */
ret = USBStorage_GetCapacity(&sector_size);
if (ret == 0)
return -1;
/* Swap endianess */ /* Read partition table */
for (cnt = 0; cnt < 4; cnt++) { ret = USBStorage_ReadSectors(0, 1, &table);
partitionEntry *entry = &table.entries[cnt]; if (ret < 0)
return ret;
entry->sector = swap32(entry->sector); break;
entry->size = swap32(entry->size); }
}
/* Set partition entries */ case WBFS_DEVICE_SDHC: {
memcpy(outbuf, table.entries, sizeof(table.entries)); /* SDHC sector size */
sector_size = SDHC_SECTOR_SIZE;
/* Set sector size */ /* Read partition table */
*outval = sector_size; ret = SDHC_ReadSectors(0, 1, &table);
if (!ret)
return -1;
return 0; break;
}
default:
return -1;
}
/* Swap endianess */
for (cnt = 0; cnt < 4; cnt++) {
partitionEntry *entry = &table.entries[cnt];
entry->sector = swap32(entry->sector);
entry->size = swap32(entry->size);
}
/* Set partition entries */
memcpy(outbuf, table.entries, sizeof(table.entries));
/* Set sector size */
*outval = sector_size;
return 0;
} }
s32 Partition_GetEntriesEx(partitionEntry *outbuf, u32 *outval, int *num) bool Device_ReadSectors(u32 device, u32 sector, u32 count, void *buffer)
{
s32 ret;
/* Read from specified device */
switch (device) {
case WBFS_DEVICE_USB:
ret = USBStorage_ReadSectors(sector, count, buffer);
if (ret < 0)
return false;
return true;
case WBFS_DEVICE_SDHC:
return SDHC_ReadSectors(sector, count, buffer);
}
return false;
}
bool Device_WriteSectors(u32 device, u32 sector, u32 count, void *buffer)
{
s32 ret;
/* Read from specified device */
switch (device) {
case WBFS_DEVICE_USB:
ret = USBStorage_WriteSectors(sector, count, buffer);
if (ret < 0)
return false;
return true;
case WBFS_DEVICE_SDHC:
return SDHC_WriteSectors(sector, count, buffer);
}
return false;
}
s32 Partition_GetEntriesEx(u32 device, partitionEntry *outbuf, u32 *psect_size, int *num)
{ {
static partitionTable table ATTRIBUTE_ALIGN(32); static partitionTable table ATTRIBUTE_ALIGN(32);
partitionEntry *entry; partitionEntry *entry;
@ -61,34 +127,60 @@ s32 Partition_GetEntriesEx(partitionEntry *outbuf, u32 *outval, int *num)
int maxpart = *num; int maxpart = *num;
// Get sector size // Get sector size
ret = USBStorage_GetCapacity(&sector_size); switch (device) {
if (ret == 0) return -1; case WBFS_DEVICE_USB:
ret = USBStorage_GetCapacity(&sector_size);
if (ret == 0) return -1;
break;
case WBFS_DEVICE_SDHC:
sector_size = SDHC_SECTOR_SIZE;
break;
default:
return -1;
}
/* Set sector size */
*psect_size = sector_size;
u32 ext = 0; u32 ext = 0;
u32 next = 0; u32 next = 0;
// Read partition table // Read partition table
ret = USBStorage_ReadSectors(0, 1, &table); ret = Device_ReadSectors(device, 0, 1, &table);
if (!ret) return -1; if (!ret) return -1;
// Check if it's a RAW WBFS disc, without partition table
if (get_fs_type(&table) == FS_TYPE_WBFS) {
memset(outbuf, 0, sizeof(table.entries));
wbfs_head_t *head = (wbfs_head_t*)&table;
outbuf->size = wbfs_ntohl(head->n_hd_sec);
*num = 1;
return 0;
}
/* Swap endianess */ /* Swap endianess */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
entry = &table.entries[i]; entry = &table.entries[i];
entry->sector = swap32(entry->sector); entry->sector = swap32(entry->sector);
entry->size = swap32(entry->size); entry->size = swap32(entry->size);
if (!ext && entry->type == 0x0f) ext = entry->sector; if (!ext && part_is_extended(entry->type)) {
ext = entry->sector;
}
} }
/* Set partition entries */ /* Set partition entries */
memcpy(outbuf, table.entries, sizeof(table.entries)); memcpy(outbuf, table.entries, sizeof(table.entries));
/* Set sector size */
*outval = sector_size;
// num primary // num primary
*num = 4; *num = 4;
if (!ext) return 0;
next = ext; next = ext;
// scan extended partition for logical // scan extended partition for logical
if (ext) for(i=0; i<maxpart-4; i++) { for(i=0; i<maxpart-4; i++) {
ret = USBStorage_ReadSectors(next, 1, &table); ret = Device_ReadSectors(device, next, 1, &table);
if (!ret) break; if (!ret) break;
if (i == 0) {
// handle the invalid scenario where wbfs is on an EXTENDED
// partition instead of on the Logical inside Extended.
if (get_fs_type(&table) == FS_TYPE_WBFS) break;
}
entry = &table.entries[0]; entry = &table.entries[0];
entry->sector = swap32(entry->sector); entry->sector = swap32(entry->sector);
entry->size = swap32(entry->size); entry->size = swap32(entry->size);
@ -106,12 +198,32 @@ s32 Partition_GetEntriesEx(partitionEntry *outbuf, u32 *outval, int *num)
break; break;
} }
} }
} }
return 0; return 0;
} }
bool part_is_extended(int type)
{
if (type == 0x05) return true;
if (type == 0x0f) return true;
return false;
}
bool part_is_data(int type)
{
if (type && !part_is_extended(type)) return true;
return false;
}
bool part_valid_data(partitionEntry *entry)
{
if (entry->size && entry->type && entry->sector) {
return part_is_data(entry->type);
}
return false;
}
char* part_type_data(int type) char* part_type_data(int type)
{ {
switch (type) { switch (type) {
@ -133,8 +245,20 @@ char* part_type_data(int type)
return NULL; return NULL;
} }
int get_fs_type(char *buf) char *part_type_name(int type)
{ {
static char unk[8];
if (type == 0) return "UNUSED";
if (part_is_extended(type)) return "EXTEND";
char *p = part_type_data(type);
if (p) return p;
sprintf(unk, "UNK-%02x", type);
return unk;
}
int get_fs_type(void *buff)
{
char *buf = buff;
// WBFS // WBFS
wbfs_head_t *head = (wbfs_head_t *)buf; wbfs_head_t *head = (wbfs_head_t *)buf;
if (head->magic == wbfs_htonl(WBFS_MAGIC)) return FS_TYPE_WBFS; if (head->magic == wbfs_htonl(WBFS_MAGIC)) return FS_TYPE_WBFS;
@ -154,7 +278,19 @@ bool is_type_fat(int type)
return (type == FS_TYPE_FAT16 || type == FS_TYPE_FAT32); return (type == FS_TYPE_FAT16 || type == FS_TYPE_FAT32);
} }
s32 Partition_GetList(PartList *plist)
char *get_fs_name(int i)
{
switch (i) {
case FS_TYPE_FAT16: return "FAT16";
case FS_TYPE_FAT32: return "FAT32";
case FS_TYPE_NTFS: return "NTFS";
case FS_TYPE_WBFS: return "WBFS";
}
return "";
}
s32 Partition_GetList(u32 device, PartList *plist)
{ {
partitionEntry *entry = NULL; partitionEntry *entry = NULL;
PartInfo *pinfo = NULL; PartInfo *pinfo = NULL;
@ -164,10 +300,19 @@ s32 Partition_GetList(PartList *plist)
// Get partition entries // Get partition entries
plist->num = MAX_PARTITIONS_EX; plist->num = MAX_PARTITIONS_EX;
ret = Partition_GetEntriesEx(plist->pentry, &plist->sector_size, &plist->num); ret = Partition_GetEntriesEx(device, plist->pentry, &plist->sector_size, &plist->num);
if (ret < 0) { if (ret < 0) {
return -1; return -1;
} }
// check for RAW WBFS disc
if (plist->num == 1) {
pinfo = &plist->pinfo[0];
entry = &plist->pentry[0];
plist->wbfs_n = 1;
pinfo->wbfs_i = 1;
return 0;
}
char buf[plist->sector_size]; char buf[plist->sector_size];
// scan partitions for filesystem type // scan partitions for filesystem type
@ -175,10 +320,15 @@ s32 Partition_GetList(PartList *plist)
pinfo = &plist->pinfo[i]; pinfo = &plist->pinfo[i];
entry = &plist->pentry[i]; entry = &plist->pentry[i];
if (!entry->size) continue; if (!entry->size) continue;
if (!part_type_data(entry->type)) continue; if (!entry->type) continue;
if (!USBStorage_ReadSectors(entry->sector, 1, buf)) continue; if (!entry->sector) continue;
// even though wrong, it's possible WBFS is on an extended part.
//if (!part_is_data(entry->type)) continue;
if (!Device_ReadSectors(device, entry->sector, 1, buf)) continue;
pinfo->fs_type = get_fs_type(buf); pinfo->fs_type = get_fs_type(buf);
if (pinfo->fs_type == FS_TYPE_WBFS) { if (pinfo->fs_type == FS_TYPE_WBFS) {
// multiple wbfs on sdhc not supported
if (device == WBFS_DEVICE_SDHC && (plist->wbfs_n > 1 || i > 4)) continue;
plist->wbfs_n++; plist->wbfs_n++;
pinfo->wbfs_i = plist->wbfs_n; pinfo->wbfs_i = plist->wbfs_n;
} else if (is_type_fat(pinfo->fs_type)) { } else if (is_type_fat(pinfo->fs_type)) {
@ -188,3 +338,24 @@ s32 Partition_GetList(PartList *plist)
} }
return 0; return 0;
} }
int Partition_FixEXT(u32 device, int part)
{
static partitionTable table ATTRIBUTE_ALIGN(32);
int ret;
if (part < 0 || part > 3) return -1;
// Read partition table
ret = Device_ReadSectors(device, 0, 1, &table);
if (!ret) return -1;
if (part_is_extended(table.entries[part].type)) {
table.entries[part].type = 0x0b; // FAT32
ret = Device_WriteSectors(device, 0, 1, &table);
if (!ret) return -1;
return 0;
}
return -1;
}

View File

@ -1,62 +1,74 @@
#ifndef _PARTITION_H_ #ifndef _PARTITION_H_
#define _PARTITION_H_ #define _PARTITION_H_
#ifdef __cplusplus
extern "C" {
#endif
/* 'partition entry' structure */
typedef struct {
/* Boot indicator */
u8 boot;
/* Starting CHS */ #ifdef __cplusplus
u8 start[3]; extern "C" {
#endif
/* Partition type */ /* 'partition entry' structure */
u8 type; typedef struct {
/* Boot indicator */
u8 boot;
/* Ending CHS */ /* Starting CHS */
u8 end[3]; u8 start[3];
/* Partition sector */ /* Partition type */
u32 sector; u8 type;
/* Partition size */ /* Ending CHS */
u32 size; u8 end[3];
} ATTRIBUTE_PACKED partitionEntry;
/* Constants */ /* Partition sector */
#define MAX_PARTITIONS 4 u32 sector;
#define MAX_PARTITIONS_EX 10
#define FS_TYPE_UNK 0 /* Partition size */
#define FS_TYPE_FAT16 1 u32 size;
#define FS_TYPE_FAT32 2 } ATTRIBUTE_PACKED partitionEntry;
#define FS_TYPE_NTFS 3
#define FS_TYPE_WBFS 4
typedef struct /* Constants */
{ #define MAX_PARTITIONS 4
int fs_type; #define MAX_PARTITIONS_EX 10
int wbfs_i; // seq wbfs part index
int fat_i; // seq fat part index
} PartInfo;
typedef struct #define FS_TYPE_UNK 0
{ #define FS_TYPE_FAT16 1
int num; #define FS_TYPE_FAT32 2
u32 sector_size; #define FS_TYPE_NTFS 3
partitionEntry pentry[MAX_PARTITIONS_EX]; #define FS_TYPE_WBFS 4
int wbfs_n;
int fat_n;
PartInfo pinfo[MAX_PARTITIONS_EX];
} PartList;
/* Prototypes */ typedef struct
s32 Partition_GetEntries(partitionEntry *, u32 *); {
s32 Partition_GetEntriesEx(partitionEntry *, u32 *, int *); int fs_type;
s32 Partition_GetList(PartList *plist); int wbfs_i; // seq wbfs part index
int fat_i; // seq fat part index
} PartInfo;
typedef struct
{
int num;
u32 sector_size;
partitionEntry pentry[MAX_PARTITIONS_EX];
int wbfs_n;
int fat_n;
PartInfo pinfo[MAX_PARTITIONS_EX];
} PartList;
/* Prototypes */
s32 Partition_GetEntries(u32 device, partitionEntry *outbuf, u32 *outval);
s32 Partition_GetEntriesEx(u32 device, partitionEntry *outbuf, u32 *outval, int *num);
bool Device_ReadSectors(u32 device, u32 sector, u32 count, void *buffer);
bool Device_WriteSectors(u32 device, u32 sector, u32 count, void *buffer);
s32 Partition_GetList(u32 device, PartList *plist);
int Partition_FixEXT(u32 device, int part);
bool part_is_extended(int type);
bool part_is_data(int type);
char* part_type_data(int type);
char* part_type_name(int type);
bool part_valid_data(partitionEntry *entry);
int get_fs_type(void *buf);
bool is_type_fat(int type);
char* get_fs_name(int i);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -52,7 +52,7 @@ static s32 hid = -1, fd = -1;
static u32 sector_size; static u32 sector_size;
extern void* SYS_AllocArena2MemLo(u32 size,u32 align); extern void* SYS_AllocArena2MemLo(u32 size,u32 align);
static void *mem2_ptr=NULL; //static void *mem2_ptr=NULL;
inline s32 __USBStorage_isMEM2Buffer(const void *buffer) { inline s32 __USBStorage_isMEM2Buffer(const void *buffer) {
u32 high_addr = ((u32)buffer) >> 24; u32 high_addr = ((u32)buffer) >> 24;
@ -151,7 +151,7 @@ void USBStorage_Deinit(void) {
s32 USBStorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) { s32 USBStorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) {
void *buf = (void *)buffer; // void *buf = (void *)buffer;
u32 len = (sector_size * numSectors); u32 len = (sector_size * numSectors);
s32 ret; s32 ret;
@ -159,30 +159,31 @@ s32 USBStorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) {
/* Device not opened */ /* Device not opened */
if (fd < 0) if (fd < 0)
return fd; return fd;
if(!mem2_ptr) mem2_ptr=SYS_AllocArena2MemLo(2048*256,32);
// if(!mem2_ptr) mem2_ptr=SYS_AllocArena2MemLo(2048*256,32);
/* MEM1 buffer */ /* MEM1 buffer */
if (!__USBStorage_isMEM2Buffer(buffer)) { // if (!__USBStorage_isMEM2Buffer(buffer)) {
/* Allocate memory */ /* Allocate memory */
buf = mem2_ptr; //iosAlloc(hid, len); // buf = mem2_ptr; //iosAlloc(hid, len);
if (!buf) // if (!buf)
return IPC_ENOMEM; // return IPC_ENOMEM;
} // }
/* Read data */ /* Read data */
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, numSectors, buf, len); ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, numSectors, buffer, len);
/* Copy data */ /* Copy data */
if (buf != buffer) { // if (buf != buffer) {
memcpy(buffer, buf, len); // memcpy(buffer, buf, len);
//iosFree(hid, buf); //iosFree(hid, buf);
} // }
return ret; return ret;
} }
s32 USBStorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) { s32 USBStorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) {
void *buf = (void *)buffer; // void *buf = (void *)buffer;
u32 len = (sector_size * numSectors); u32 len = (sector_size * numSectors);
s32 ret; s32 ret;
@ -190,26 +191,26 @@ s32 USBStorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) {
/* Device not opened */ /* Device not opened */
if (fd < 0) if (fd < 0)
return fd; return fd;
if(!mem2_ptr) mem2_ptr = SYS_AllocArena2MemLo(2048*256,32); // if(!mem2_ptr) mem2_ptr = SYS_AllocArena2MemLo(2048*256,32);
/* MEM1 buffer */ /* MEM1 buffer */
if (!__USBStorage_isMEM2Buffer(buffer)) { // if (!__USBStorage_isMEM2Buffer(buffer)) {
/* Allocate memory */ /* Allocate memory */
buf = mem2_ptr; //buf = iosAlloc(hid, len); // buf = mem2_ptr; //buf = iosAlloc(hid, len);
if (!buf) // if (!buf)
return IPC_ENOMEM; // return IPC_ENOMEM;
/* Copy data */ /* Copy data */
memcpy(buf, buffer, len); // memcpy(buf, buffer, len);
} // }
/* Write data */ /* Write data */
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, numSectors, buf, len); ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, numSectors, buffer, len);
/* Free memory */ /* Free memory */
if (buf != buffer) // if (buf != buffer)
iosFree(hid, buf); // iosFree(hid, buf);
return ret; return ret;
} }

View File

@ -338,7 +338,7 @@ s32 WBFS_OpenNamed(char *partition)
} }
// Get partition entries // Get partition entries
ret = Partition_GetList(&plist); ret = Partition_GetList(wbfsDev, &plist);
if (ret || plist.num == 0) return -1; if (ret || plist.num == 0) return -1;
if (part_fat) { if (part_fat) {

View File

@ -24,8 +24,11 @@
#include "disc.h" #include "disc.h"
#include "settings/cfg.h" #include "settings/cfg.h"
// WBFS FAT by oggzee // WBFS FAT by oggzee
// max fat fname = 256
#define MAX_FAT_PATH 1024
#define D_S(A) A, sizeof(A) #define D_S(A) A, sizeof(A)
char wbfs_fat_drive[16]; char wbfs_fat_drive[16];
@ -42,36 +45,38 @@ static u32 fat_sector_size = 512;
void WBFS_Spinner(s32 x, s32 max); void WBFS_Spinner(s32 x, s32 max);
s32 __WBFS_ReadDVD(void *fp, u32 lba, u32 len, void *iobuf); s32 __WBFS_ReadDVD(void *fp, u32 lba, u32 len, void *iobuf);
s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len) s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len)
{ {
DIR *dir; DIR *dir;
struct dirent *dent; struct dirent *dent;
char *p; char *p;
int ret, cnt = 0; int ret, cnt = 0;
char path[100]; char path[MAX_FAT_PATH];
wbfs_t *part = NULL; wbfs_t *part = NULL;
u32 size; u32 size;
u8 *ptr; u8 *ptr;
struct discHdr tmpHdr; struct discHdr tmpHdr;
int hdrsize; int hdrsize;
struct stat st; struct stat st;
u8 id[8];
int is_dir;
//dbg_time1(); //dbg_time1();
strcpy(path, wbfs_fat_drive); strcpy(path, wbfs_fat_drive);
strcat(path, wbfs_fat_dir); strcat(path, wbfs_fat_dir);
dir = opendir(path); dir = opendir(path);
//printf("opendir: %s %p\n", path, dir); Wpad_WaitButtons();
if (!dir) { if (!dir) {
*count = 0; *count = 0;
return 0; return 0;
} }
while ((dent = readdir(dir)) != NULL) { while ((dent = readdir(dir)) != NULL) {
//printf("found: %s\n", dent->d_name);
if (outbuf && cnt >= *count) break; if (outbuf && cnt >= *count) break;
if ((char)dent->d_name[0] == '.') continue; if ((char)dent->d_name[0] == '.') continue;
p = strrchr(dent->d_name, '.'); if (strlen(dent->d_name) < 8) continue; // "GAMEID_x"
if (!p) continue;
if (strcasecmp(p, ".wbfs") != 0) continue;
if (strlen(dent->d_name) != 11) continue; // GAMEID.wbfs
u8 id[8];
memcpy(id, dent->d_name, 6); memcpy(id, dent->d_name, 6);
id[6] = 0; id[6] = 0;
@ -80,6 +85,26 @@ s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len)
strcat(path, "/"); strcat(path, "/");
strcat(path, dent->d_name); strcat(path, dent->d_name);
stat(path, &st); stat(path, &st);
is_dir = S_ISDIR(st.st_mode);
//printf("path: %s %d\n", path, is_dir);
if (is_dir) {
// usb:/wbfs/GAMEID_TITLE/GAMEID.wbfs
if (dent->d_name[6] != '_') continue;
strcat(path, "/");
strcat(path, (char*)id);
strcat(path, ".wbfs");
//printf("path2: %s\n", path);
if (stat(path, &st) == -1) continue;
} else {
// usb:/wbfs/GAMEID.wbfs
p = strrchr(dent->d_name, '.');
if (!p) continue;
if (strcasecmp(p, ".wbfs") != 0) continue;
if (strlen(dent->d_name) != 11) continue; // GAMEID.wbfs
}
//printf("found: %s %d MB\n", path, (int)(st.st_size/1024/1024));
// size must be at least 1MB to be considered a valid wbfs file // size must be at least 1MB to be considered a valid wbfs file
if (st.st_size < 1024*1024) continue; if (st.st_size < 1024*1024) continue;
if (!outbuf) { if (!outbuf) {
@ -89,40 +114,43 @@ s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len)
} }
ptr = ((u8 *)outbuf) + (cnt * len); ptr = ((u8 *)outbuf) + (cnt * len);
hdrsize = len; hdrsize = len;
// if we have titles.txt entry use that
char *title = cfg_get_title(id); char *title = cfg_get_title(id);
// if directory, and no titles.txt get title from dir name
if (!title && is_dir) {
title = &dent->d_name[7];
}
if (title) { if (title) {
memset(&tmpHdr, 0, sizeof(tmpHdr)); memset(&tmpHdr, 0, sizeof(tmpHdr));
memcpy(tmpHdr.id, id, 6); memcpy(tmpHdr.id, id, 6);
strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)); strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)-1);
tmpHdr.magic = 0x5D1C9EA3; tmpHdr.magic = 0x5D1C9EA3;
memcpy(ptr, &tmpHdr, hdrsize); memcpy(ptr, &tmpHdr, hdrsize);
cnt++; cnt++;
continue; continue;
} }
// no title found, read it from wbfs file directly // else read it from wbfs file directly
FILE *fp = fopen(path, "rb"); FILE *fp = fopen(path, "rb");
if (fp != NULL) { if (fp != NULL) {
fseek(fp, 512, SEEK_SET); fseek(fp, 512, SEEK_SET);
fread(&tmpHdr, sizeof(struct discHdr), 1, fp); fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
fclose(fp); fclose(fp);
if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0)) {
if (tmpHdr.magic == 0x5D1C9EA3 && (memcmp(tmpHdr.id, id, 6) == 0)) {
memcpy(ptr, &tmpHdr, hdrsize); memcpy(ptr, &tmpHdr, hdrsize);
cnt++; cnt++;
continue; continue;
} }
} }
// no title found, read it from wbfs file // no title found, read it from wbfs file
// but this is a little bit slower // but this is a little bit slower
// open 'partition' file // open 'partition' file
part = WBFS_FAT_OpenPart(id); part = WBFS_FAT_OpenPart(id);
if (!part) { if (!part) {
printf("bad wbfs file: %s\n", dent->d_name);
sleep(2);
continue; continue;
} }
/* Get header */ /* Get header */
ret = wbfs_get_disc_info(part, 0, ptr, hdrsize, &size); ret = wbfs_get_disc_info(part, 0, ptr, hdrsize, &size);
if (ret == 0) cnt++; if (ret == 0) cnt++;
@ -131,7 +159,7 @@ s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len)
*count = cnt; *count = cnt;
closedir(dir); closedir(dir);
//dbg_time2("\nFAT HDRS"); //dbg_time2("\nFAT HDRS");
//Wpad_WaitButtons(); //Wpad_WaitButtonsCommon();
return 0; return 0;
} }
@ -175,7 +203,6 @@ s32 WBFS_FAT_DiskSpace(f32 *used, f32 *free)
// statvfs is slow, so cache values // statvfs is slow, so cache values
if (!wbfs_fat_vfs_have || wbfs_fat_vfs_lba != wbfs_part_lba) { if (!wbfs_fat_vfs_have || wbfs_fat_vfs_lba != wbfs_part_lba) {
ret = statvfs(wbfs_fat_drive, &wbfs_fat_vfs); ret = statvfs(wbfs_fat_drive, &wbfs_fat_vfs);
if (ret) return 0; if (ret) return 0;
wbfs_fat_vfs_have = 1; wbfs_fat_vfs_have = 1;
wbfs_fat_vfs_lba = wbfs_part_lba; wbfs_fat_vfs_lba = wbfs_part_lba;
@ -192,32 +219,122 @@ s32 WBFS_FAT_DiskSpace(f32 *used, f32 *free)
static int nop_read_sector(void *_fp,u32 lba,u32 count,void*buf) static int nop_read_sector(void *_fp,u32 lba,u32 count,void*buf)
{ {
//printf("read %d %d\n", lba, count); //Wpad_WaitButtons();
return 0; return 0;
} }
static int nop_write_sector(void *_fp,u32 lba,u32 count,void*buf) static int nop_write_sector(void *_fp,u32 lba,u32 count,void*buf)
{ {
//printf("write %d %d\n", lba, count); //Wpad_WaitButtons();
return 0; return 0;
} }
void WBFS_FAT_fname(u8 *id, char *fname, int len) void WBFS_FAT_fname(u8 *id, char *fname, int len, char *path)
{ {
snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fat_drive, wbfs_fat_dir, id); if (path == NULL) {
snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fat_drive, wbfs_fat_dir, id);
} else {
snprintf(fname, len, "%s/%.6s.wbfs", path, id);
}
}
void mk_gameid_title(struct discHdr *header, char *name, int re_space)
{
int i, len;
memcpy(name, header->id, 6);
name[6] = 0;
strcat(name, "_");
strcat(name, get_title(header));
// replace silly chars with '_'
len = strlen(name);
for (i = 0; i < len; i++) {
if(strchr("\\/:<>|\"", name[i]) || iscntrl(name[i])) {
name[i] = '_';
}
if(re_space && name[i]==' ') {
name[i] = '_';
}
}
}
void WBFS_FAT_get_dir(struct discHdr *header, char *path)
{
strcpy(path, wbfs_fat_drive);
strcat(path, wbfs_fat_dir);
if (Settings.FatInstallToDir) {
strcat(path, "/");
mk_gameid_title(header, path + strlen(path), 0);
}
}
void mk_title_txt(struct discHdr *header, char *path)
{
char fname[MAX_FAT_PATH];
FILE *f;
strcpy(fname, path);
strcat(fname, "/");
mk_gameid_title(header, fname+strlen(fname), 1);
strcat(fname, ".txt");
f = fopen(fname, "wb");
if (!f) return;
fprintf(f, "%.6s = %.64s\n", header->id, get_title(header));
fclose(f);
printf("Info file: %s\n", fname);
}
int WBFS_FAT_find_fname(u8 *id, char *fname, int len)
{
struct stat st;
WBFS_FAT_fname(id, fname, len, NULL);
if (stat(fname, &st) == 0) return 1;
// direct file not found, check subdirs
DIR *dir;
struct dirent *dent;
char path[MAX_FAT_PATH];
strcpy(path, wbfs_fat_drive);
strcat(path, wbfs_fat_dir);
dir = opendir(path);
//printf("opendir: %s %p\n", path, dir); Wpad_WaitButtons();
if (!dir) {
goto err;
}
while ((dent = readdir(dir)) != NULL) {
char *name = (char*)dent->d_name;
if (name[0] == '.') continue;
if (name[6] != '_') continue;
if (strncmp(name, (char*)id, 6) != 0) continue;
if (strlen(name) < 8) continue;
snprintf(fname, len, "%s/%s/%.6s.wbfs", path, name, id);
if (stat(fname, &st) == 0) {
closedir(dir);
return 2;
}
}
closedir(dir);
// not found
err:
*fname = 0;
return 0;
} }
wbfs_t* WBFS_FAT_OpenPart(u8 *id) wbfs_t* WBFS_FAT_OpenPart(u8 *id)
{ {
char fname[100]; char fname[MAX_FAT_PATH];
wbfs_t *part = NULL; wbfs_t *part = NULL;
int ret; int ret;
// wbfs 'partition' file // wbfs 'partition' file
WBFS_FAT_fname(id, fname, sizeof(fname)); if ( !WBFS_FAT_find_fname(id, fname, sizeof(fname)) ) return NULL;
ret = split_open(&split, fname); ret = split_open(&split, fname);
if (ret) return NULL; if (ret) return NULL;
part = wbfs_open_partition( part = wbfs_open_partition(
split_read_sector, split_read_sector,
split_write_sector, //readonly //split_write_sector, nop_write_sector, //readonly //split_write_sector,
&split, fat_sector_size, split.total_sec, 0, 0); &split, fat_sector_size, split.total_sec, 0, 0);
if (!part) { if (!part) {
split_close(&split); split_close(&split);
@ -225,17 +342,20 @@ wbfs_t* WBFS_FAT_OpenPart(u8 *id)
return part; return part;
} }
wbfs_t* WBFS_FAT_CreatePart(u8 *id) wbfs_t* WBFS_FAT_CreatePart(u8 *id, char *path)
{ {
char fname[100]; char fname[MAX_FAT_PATH];
wbfs_t *part = NULL; wbfs_t *part = NULL;
u64 size = (u64)143432*2*0x8000ULL; u64 size = (u64)143432*2*0x8000ULL;
u32 n_sector = size / 512; u32 n_sector = size / 512;
int ret; int ret;
//printf("CREATE PART %s %lld %d\n", id, size, n_sector);
snprintf(D_S(fname), "%s%s", wbfs_fat_drive, wbfs_fat_dir); snprintf(D_S(fname), "%s%s", wbfs_fat_drive, wbfs_fat_dir);
mkdir(fname, 0777); mkdir(fname, 0777); // base usb:/wbfs
WBFS_FAT_fname(id, fname, sizeof(fname)); mkdir(path, 0777); // game subdir
WBFS_FAT_fname(id, fname, sizeof(fname), path);
printf("Writing to %s\n", fname);
ret = split_create(&split, fname, OPT_split_size, size, true); ret = split_create(&split, fname, OPT_split_size, size, true);
if (ret) return NULL; if (ret) return NULL;
@ -243,6 +363,8 @@ wbfs_t* WBFS_FAT_CreatePart(u8 *id)
u32 scnt = 0; u32 scnt = 0;
int fd = split_get_file(&split, 0, &scnt, 0); int fd = split_get_file(&split, 0, &scnt, 0);
if (fd<0) { if (fd<0) {
printf("ERROR creating file\n");
sleep(2);
split_close(&split); split_close(&split);
return NULL; return NULL;
} }
@ -267,42 +389,87 @@ void WBFS_FAT_ClosePart(wbfs_t* part)
s32 WBFS_FAT_RemoveGame(u8 *discid) s32 WBFS_FAT_RemoveGame(u8 *discid)
{ {
char fname[100]; char fname[MAX_FAT_PATH];
int loc;
// wbfs 'partition' file // wbfs 'partition' file
WBFS_FAT_fname(discid, fname, sizeof(fname)); loc = WBFS_FAT_find_fname(discid, fname, sizeof(fname));
if ( !loc ) return -1;
split_create(&split, fname, 0, 0, true); split_create(&split, fname, 0, 0, true);
split_close(&split); split_close(&split);
if (loc == 1) return 0;
// game is in subdir
// remove optional .txt file
DIR *dir;
struct dirent *dent;
char path[MAX_FAT_PATH];
strncpy(path, fname, sizeof(path));
char *p= strrchr(path, '/');
if (p) *p = 0;
dir = opendir(path);
if (!dir) return 0;
while ((dent = readdir(dir)) != NULL) {
char *name = (char*)dent->d_name;
if (name[0] == '.') continue;
if (name[6] != '_') continue;
if (strncmp(name, (char*)discid, 6) != 0) continue;
p = strrchr(name, '.');
if (!p) continue;
if (strcasecmp(p, ".txt") != 0) continue;
snprintf(fname, sizeof(fname), "%s/%s", path, name);
remove(fname);
break;
}
closedir(dir);
// remove game subdir
//rmdir(path);
if (unlink(path) == -1) {
}
// Reset FAT stats
wbfs_fat_vfs_have = 0;
return 0; return 0;
} }
s32 WBFS_FAT_AddGame(void) s32 WBFS_FAT_AddGame(void)
{ {
static struct discHdr header ATTRIBUTE_ALIGN(32); static struct discHdr header ATTRIBUTE_ALIGN(32);
s32 ret; char path[MAX_FAT_PATH];
wbfs_t *part = NULL; wbfs_t *part = NULL;
s32 ret;
//write_test(); return -1;
// read ID from DVD // read ID from DVD
Disc_ReadHeader(&header); Disc_ReadHeader(&header);
// path
WBFS_FAT_get_dir(&header, path);
// create wbfs 'partition' file // create wbfs 'partition' file
part = WBFS_FAT_CreatePart(header.id); part = WBFS_FAT_CreatePart(header.id, path);
if (!part) return -1; if (!part) return -1;
/* Add game to device */ /* Add game to device */
partition_selector_t part_sel = ONLY_GAME_PARTITION;
int copy_1_1 = 0;
/*
switch (CFG.install_partitions) {
case CFG_INSTALL_GAME:
part_sel = ONLY_GAME_PARTITION;
break;
case CFG_INSTALL_ALL:
part_sel = ALL_PARTITIONS;
break;
case CFG_INSTALL_1_1:
part_sel = ALL_PARTITIONS;
copy_1_1 = 1;
break;
}
*/
extern wbfs_t *hdd; extern wbfs_t *hdd;
wbfs_t *old_hdd = hdd; wbfs_t *old_hdd = hdd;
hdd = part; // used by spinner hdd = part; // used by spinner
ret = wbfs_add_disc(part, __WBFS_ReadDVD, NULL, WBFS_Spinner, ONLY_GAME_PARTITION, 0); ret = wbfs_add_disc(part, __WBFS_ReadDVD, NULL, WBFS_Spinner, part_sel, copy_1_1);
hdd = old_hdd; hdd = old_hdd;
wbfs_trim(part); wbfs_trim(part);
WBFS_FAT_ClosePart(part); WBFS_FAT_ClosePart(part);
// Reset FAT stats
wbfs_fat_vfs_have = 0;
if (ret < 0) return ret; if (ret < 0) return ret;
mk_title_txt(&header, path);
return 0; return 0;
} }
@ -315,7 +482,7 @@ s32 WBFS_FAT_DVD_Size(u64 *comp_size, u64 *real_size)
wbfs_t *part = NULL; wbfs_t *part = NULL;
u64 size = (u64)143432*2*0x8000ULL; u64 size = (u64)143432*2*0x8000ULL;
u32 n_sector = size / fat_sector_size; u32 n_sector = size / fat_sector_size;
u32 wii_sec_sz; u32 wii_sec_sz;
// init a temporary dummy part // init a temporary dummy part
// as a placeholder for wbfs_size_disc // as a placeholder for wbfs_size_disc
@ -326,13 +493,21 @@ s32 WBFS_FAT_DVD_Size(u64 *comp_size, u64 *real_size)
wii_sec_sz = part->wii_sec_sz; wii_sec_sz = part->wii_sec_sz;
/* Add game to device */ /* Add game to device */
ret = wbfs_size_disc(part, __WBFS_ReadDVD, NULL, ONLY_GAME_PARTITION, &comp_sec, &last_sec); partition_selector_t part_sel = ONLY_GAME_PARTITION;
/*
if (CFG.install_partitions) {
part_sel = ALL_PARTITIONS;
} else {
part_sel = ONLY_GAME_PARTITION;
}
*/
ret = wbfs_size_disc(part, __WBFS_ReadDVD, NULL, part_sel, &comp_sec, &last_sec);
wbfs_close(part); wbfs_close(part);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (comp_size != NULL) *comp_size = (u64)wii_sec_sz * comp_sec; *comp_size = (u64)wii_sec_sz * comp_sec;
if (real_size != NULL) *real_size = (u64)wii_sec_sz * last_sec; *real_size = (u64)wii_sec_sz * last_sec;
return 0; return 0;
} }
@ -366,8 +541,8 @@ s32 WBFS_FAT_ReIDGame(u8 *discid, const void *newID)
char fnamenew[100]; char fnamenew[100];
s32 cnt = 0x31; s32 cnt = 0x31;
WBFS_FAT_fname(discid, fname, sizeof(fname)); WBFS_FAT_fname(discid, fname, sizeof(fname), NULL);
WBFS_FAT_fname((u8*) newID, fnamenew, sizeof(fnamenew)); WBFS_FAT_fname((u8*) newID, fnamenew, sizeof(fnamenew), NULL);
int stringlength = strlen(fname); int stringlength = strlen(fname);

View File

@ -15,6 +15,7 @@
#define IOCTL_DI_SEEK 0xAB #define IOCTL_DI_SEEK 0xAB
#define IOCTL_DI_STOPLASER 0xD2 #define IOCTL_DI_STOPLASER 0xD2
#define IOCTL_DI_OFFSET 0xD9 #define IOCTL_DI_OFFSET 0xD9
#define IOCTL_DI_DISC_BCA 0xDA
#define IOCTL_DI_STOPMOTOR 0xE3 #define IOCTL_DI_STOPMOTOR 0xE3
#define IOCTL_DI_SETUSBMODE 0xF4 #define IOCTL_DI_SETUSBMODE 0xF4
#define IOCTL_DI_DISABLERESET 0xF6 #define IOCTL_DI_DISABLERESET 0xF6
@ -336,3 +337,20 @@ s32 WDVD_SetUSBMode(const u8 *id, s32 partition) {
return (ret == 1) ? 0 : -ret; return (ret == 1) ? 0 : -ret;
} }
s32 WDVD_Read_Disc_BCA(void *buf)
{
s32 ret;
memset(inbuf, 0, sizeof(inbuf));
/* Disc read */
inbuf[0] = IOCTL_DI_DISC_BCA << 24;
//inbuf[1] = 64;
ret = IOS_Ioctl(di_fd, IOCTL_DI_DISC_BCA, inbuf, sizeof(inbuf), buf, 64);
if (ret < 0)
return ret;
return (ret == 1) ? 0 : -ret;
}

View File

@ -23,6 +23,7 @@ extern "C" {
s32 WDVD_GetCoverStatus(u32 *); s32 WDVD_GetCoverStatus(u32 *);
s32 WDVD_DisableReset(u8); s32 WDVD_DisableReset(u8);
s32 WDVD_SetUSBMode(const u8 *, s32 partition); s32 WDVD_SetUSBMode(const u8 *, s32 partition);
s32 WDVD_Read_Disc_BCA(void *buf);
#ifdef __cplusplus #ifdef __cplusplus
} }