diff --git a/Makefile b/Makefile
index 9ec65392..132c4efd 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,7 @@ SOURCES := source source/libwiigui source/images source/fonts source/sounds \
source/libwbfs source/unzip source/language source/mload source/patches \
source/usbloader source/xml source/network source/settings source/prompts \
source/ramdisc source/wad source/banner source/cheats source/homebrewboot
+DATA := data
INCLUDES := source
#---------------------------------------------------------------------------------
@@ -150,6 +151,13 @@ language: $(wildcard $(PROJECTDIR)/Languages/*.lang)
@echo $(notdir $<)
$(bin2o)
+%.certs.o : %.certs
+ @echo $(notdir $<)
+ $(bin2o)
+%.dat.o : %.dat
+ @echo $(notdir $<)
+ $(bin2o)
+
export PATH := $(PROJECTDIR)/gettext-bin:$(PATH)
diff --git a/data/certs.dat b/data/certs.dat
new file mode 100644
index 00000000..2184107d
Binary files /dev/null and b/data/certs.dat differ
diff --git a/data/haxx.certs b/data/haxx.certs
new file mode 100644
index 00000000..32dd50ca
Binary files /dev/null and b/data/haxx.certs differ
diff --git a/gui.pnproj b/gui.pnproj
index 58b282f6..509ea2e0 100644
--- a/gui.pnproj
+++ b/gui.pnproj
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/gui.pnps b/gui.pnps
index 9504be5f..be6e1712 100644
--- a/gui.pnps
+++ b/gui.pnps
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/source/menu.cpp b/source/menu.cpp
index 5c7fc04e..e2c863f8 100644
--- a/source/menu.cpp
+++ b/source/menu.cpp
@@ -44,6 +44,7 @@
#include "fatmounter.h"
#include "buffer.h"
#include "xml/xml.h"
+#include "wad/title.h"
#include "usbloader/wdvd.h"
@@ -706,7 +707,7 @@ int MenuDiscList()
if (Settings.godmode == 1)
w.Append(&homebrewBtn);
- if((Settings.hddinfo == hr12)||(Settings.hddinfo == hr24))
+ if((Settings.hddinfo == hr12)||(Settings.hddinfo == hr24))
{
w.Append(&clockTimeBack);
w.Append(&clockTime);
diff --git a/source/prompts/TitleBrowser.cpp b/source/prompts/TitleBrowser.cpp
index 19e451e2..30ddbd57 100644
--- a/source/prompts/TitleBrowser.cpp
+++ b/source/prompts/TitleBrowser.cpp
@@ -2,7 +2,7 @@
* TitleBrowser
* USB Loader GX 2009
*
- * TitleBrowser.cpp
+ * TitleBrowser.cpp *giantpune*
***************************************************************************/
#include "language/gettext.h"
#include "libwiigui/gui.h"
@@ -45,6 +45,8 @@ int TitleBrowser(u32 type)
FILE *f;
char path[100];
+ ISFS_Initialize();
+
sprintf(path,"%s/config/database.txt",bootDevice);
f = fopen(path, "r");
@@ -55,12 +57,6 @@ int TitleBrowser(u32 type)
//exit(1);
}
- // Die if we can't handle this many
- if (num_titles > 100){
- //printf("\tError! Too many titles! (%u)\n", num_titles);
- //exit(1);
- }
-
// Get titles of our requested type
ret = getTitles_Type(type, titles, num_titles);
if (ret < 0){
@@ -82,10 +78,11 @@ int TitleBrowser(u32 type)
//exit(1);
}
-
-
+
+ //this array will hold all the names for the titles so we only have to get them one time
+ char name[num_titles+num_sys_titles][50];
- customOptionList options3(num_titles+num_sys_titles);
+ customOptionList options3(num_titles+num_sys_titles+1);
//write the titles on the option browser
u32 i = 0;
@@ -95,45 +92,54 @@ int TitleBrowser(u32 type)
while (i < num_titles){
//start from the beginning of the file each loop
if (f)rewind(f);
- char name[50];
+ //char name[50];
char text[15];
- strcpy(name,"");//make sure name is empty
-
+ strcpy(name[i],"");//make sure name is empty
+ u8 found=0;
//set the title's name, number, ID to text
sprintf(text, "%s", titleText(type, titles[i]));
- //getTitle_Name(name, TITLE_ID(type, titles[i]), text);
//get name from database cause i dont like the ADT function
char line[200];
char tmp[50];
snprintf(tmp,50,tmp," ");
- snprintf(name,sizeof(name),"Unknown Title");
+ //snprintf(name[i],sizeof(name[i]),"Unknown Title");
- if (!f) {
- sprintf(name,"Unknown--");
- }
- else
+ if(f)
{
while (fgets(line, sizeof(line), f)) {
if (line[0]== text[0]&&
line[1]== text[1]&&
line[2]== text[2])
{ int j=0;
+ found=1;
for(j=0;(line[j+4]!='\0' || j<51);j++)
tmp[j]=line[j+4];
- snprintf(name,sizeof(name),"%s",tmp);
- break;
-
+ snprintf(name[i],sizeof(name[i]),"%s",tmp);
+ //break;
+ }
+ }
+ }
+ if(!found)
+ {
+ if (getName00(name[i], TITLE_ID(type, titles[i]),CONF_GetLanguage()*2)>=0)
+ found=2;
+
+ if(!found)
+ {
+ if (getNameBN(name[i], TITLE_ID(type, titles[i]))>=0)
+ found=3;
+
+ if(!found)
+ snprintf(name[i],sizeof(name[i]),"Unknown Title (%08x)",titles[i]);
}
-
}
- }
//set the text to the option browser
options3.SetName(i, "%s",text);
- options3.SetValue(i, "%s",name);
- //options3.SetValue(i, " (%08x)",titles[i]);//use this line to show the number to call to launch the channel
+ options3.SetValue(i, "%s",name[i]);
+ //options3.SetValue(i, " (%08x) %s",titles[i],name[i]);//use this line to show the number to call to launch the channel
//move on to the next title
i++;
}
@@ -142,49 +148,66 @@ int TitleBrowser(u32 type)
while (i < num_titles+num_sys_titles){
//start from the beginning of the file each loop
if (f)rewind(f);
- char name[50];
+ //char name[50];
char text[15];
- strcpy(name,"");//make sure name is empty
-
+ strcpy(name[i],"");//make sure name is empty
+ u8 found=0;
//set the title's name, number, ID to text
sprintf(text, "%s", titleText(0x00010002, sys_titles[i-num_titles]));
- //getTitle_Name(name, TITLE_ID(0x00010002, sys_titles[i-num_titles]), text);
//get name from database cause i dont like the ADT function
char line[200];
char tmp[50];
snprintf(tmp,50,tmp," ");
- snprintf(name,sizeof(name),"Unknown Title");
-
- if (!f) {
- sprintf(name,"Unknown--");
- }
- else
+ //snprintf(name[i],sizeof(name[i]),"Unknown Title");
+ if(f)
{
while (fgets(line, sizeof(line), f)) {
if (line[0]== text[0]&&
line[1]== text[1]&&
line[2]== text[2])
{ int j=0;
+ found=1;
for(j=0;(line[j+4]!='\0' || j<51);j++)
tmp[j]=line[j+4];
- snprintf(name,sizeof(name),"%s",tmp);
+ snprintf(name[i],sizeof(name[i]),"%s",tmp);
break;
-
}
-
+ }
+ }
+ if(!found)
+ {
+ if (getName00(name[i], TITLE_ID(0x00010002, sys_titles[i-num_titles]))>=0)
+ found=2;
+
+ if(!found)
+ {
+ if (getNameBN(name[i], TITLE_ID(0x00010002, sys_titles[i-num_titles]))>=0)
+ found=3;
+
+ if(!found)
+ snprintf(name[i],sizeof(name[i]),"Unknown Title (%08x)",sys_titles[i-num_titles]);
+ }
}
- }
//set the text to the option browser
options3.SetName(i, "%s",text);
- options3.SetValue(i, "%s",name);
- //options3.SetValue(i, " (%08x)",titles[i]);
+ options3.SetValue(i, "%s",name[i]);
+ //options3.SetValue(i, " (%08x) %s",titles[i],name[i]);//use this line to show the number to call to launch the channel
//move on to the next title
i++;
}
+ if(i == num_titles+num_sys_titles)
+ { options3.SetName(i, " ");
+ options3.SetValue(i, "%s",tr("Wii Settings"));
+ }
+ //we have all the titles we need so close the database and stop poking around in the wii
+ fclose(f);
+ //get rid of our footprints in there
+ Uninstall_FromTitle(TITLE_ID(1, 0));
+ ISFS_Deinitialize();
bool exit = false;
GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume);
@@ -231,7 +254,7 @@ int TitleBrowser(u32 type)
if(num_titles > 9)
scrollbaron = 1;
- GuiCustomOptionBrowser optionBrowser3(396, 280, &options3, CFG.theme_path, "bg_options_gamesettings.png", bg_options_settings_png, num_titles>9?1:0, 200);
+ GuiCustomOptionBrowser optionBrowser3(396, 280, &options3, CFG.theme_path, "bg_options_gamesettings.png", bg_options_settings_png, num_titles+num_sys_titles>9?1:0, 200);
optionBrowser3.SetPosition(0, 90);
optionBrowser3.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
@@ -244,6 +267,8 @@ int TitleBrowser(u32 type)
mainWindow->Append(&w);
+
+ int tmp=num_titles+num_sys_titles;
ResumeGui();
numtitle=num_titles;
while(!exit)
@@ -259,50 +284,25 @@ int TitleBrowser(u32 type)
if(ret > -1) {//if a click happened
- char name[50];
+ //char name[50];
char text[15];
if (f)rewind(f);
- strcpy(name,"");//make sure name is empty
+ //strcpy(name,"");//make sure name is empty
if (ret");
- }
- else
- {
- while (fgets(line, sizeof(line), f)) {
- if (line[0]== text[0]&&
- line[1]== text[1]&&
- line[2]== text[2])
- { int j=0;
- for(j=0;(line[j+4]!='\0' || j<51);j++)
-
- tmp[j]=line[j+4];
- snprintf(name,sizeof(name),"%s",tmp);
- break;
- }
- }
- }
char temp[100];
//prompt to boot selected title
- snprintf(temp, sizeof(temp), "%s : %s",text,name);
+ snprintf(temp, sizeof(temp), "%s : %s",text,name[ret]);
int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel"));
if(choice) {//if they say yes
//stop all this stuff before starting the channel
- fclose(f);
+
CloseXMLDatabase();
ExitGUIThreads();
ShutdownAudio();
@@ -322,59 +322,46 @@ int TitleBrowser(u32 type)
}
else//if they clicked a system title
{
- //set the title's name, number, ID to text
- sprintf(text, "%s", titleText(0x00010002, sys_titles[ret-num_titles]));
- getTitle_Name(name, TITLE_ID(0x00010002, sys_titles[ret-num_titles]), text);
-
- //get name from database cause i dont like the ADT function
- char line[200];
- char tmp[50];
- snprintf(tmp,50,tmp," ");
- snprintf(name,sizeof(name),"Unknown Title");
-
- if (!f) {
- sprintf(name,"Unknown--");
- }
- else
- {
- while (fgets(line, sizeof(line), f)) {
- if (line[0]== text[0]&&
- line[1]== text[1]&&
- line[2]== text[2])
- { int j=0;
- for(j=0;(line[j+4]!='\0' || j<51);j++)
-
- tmp[j]=line[j+4];
- snprintf(name,sizeof(name),"%s",tmp);
- break;
- }
- }
- }
- char temp[100];
- //prompt to boot selected title
- snprintf(temp, sizeof(temp), "%s : %s May not boot correctly if your System Menu is not up to date.",text,name);
- int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel"));
- if(choice) {//if they say yes
-
-
- //stop all this stuff before starting the channel
- fclose(f);
- CloseXMLDatabase();
- ExitGUIThreads();
- ShutdownAudio();
- StopGX();
+ if(ret == tmp)
+ {
+ CloseXMLDatabase();
+ ExitGUIThreads();
+ ShutdownAudio();
+ StopGX();
WII_Initialize();
- WII_LaunchTitle(TITLE_ID(0x00010002,sys_titles[ret-num_titles]));
- //this really shouldn't be needed because the title will be booted
- exit = true;
- break;
- }
- else{
- //if they said no to booting the title
- ret = -1;
- optionBrowser3.ResetState();
- }
+ WII_ReturnToSettings();
+ }
+ else
+ {
+ //set the title's name, number, ID to text
+ sprintf(text, "%s", titleText(0x00010002, sys_titles[ret-num_titles]));
+
+ char temp[100];
+ //prompt to boot selected title
+ snprintf(temp, sizeof(temp), "%s : %s May not boot correctly if your System Menu is not up to date.",text,name[ret]);
+ int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel"));
+ if(choice) {//if they say yes
+
+
+ //stop all this stuff before starting the channel
+
+ CloseXMLDatabase();
+ ExitGUIThreads();
+ ShutdownAudio();
+ StopGX();
+ WII_Initialize();
+ WII_LaunchTitle(TITLE_ID(0x00010002,sys_titles[ret-num_titles]));
+ //this really shouldn't be needed because the title will be booted
+ exit = true;
+ break;
+ }
+ else{
+ //if they said no to booting the title
+ ret = -1;
+ optionBrowser3.ResetState();
+ }
+ }
}
}
diff --git a/source/svnrev.c b/source/svnrev.c
index 0ca73268..39029821 100644
--- a/source/svnrev.c
+++ b/source/svnrev.c
@@ -1,4 +1,4 @@
-#define SVN_REV "669M"
+#define SVN_REV "672M"
const char *GetRev()
{
diff --git a/source/wad/id.c b/source/wad/id.c
new file mode 100644
index 00000000..fe77d02d
--- /dev/null
+++ b/source/wad/id.c
@@ -0,0 +1,210 @@
+/*-------------------------------------------------------------
+
+id.c -- ES Identification code
+
+Copyright (C) 2008 tona
+Unless other credit specified
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1.The origin of this software must not be misrepresented; you
+must not claim that you wrote the original software. If you use
+this software in a product, an acknowledgment in the product
+documentation would be appreciated but is not required.
+
+2.Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3.This notice may not be removed or altered from any source
+distribution.
+
+-------------------------------------------------------------*/
+
+#include
+#include
+#include
+
+#include "id.h"
+#include "patchmii_core.h"
+
+#include "certs_dat.h"
+
+
+// Turn upper and lower into a full title ID
+#define TITLE_ID(x,y) (((u64)(x) << 32) | (y))
+// Get upper or lower half of a title ID
+#define TITLE_UPPER(x) ((u32)((x) >> 32))
+// Turn upper and lower into a full title ID
+#define TITLE_LOWER(x) ((u32)(x))
+
+
+/* Debug functions adapted from libogc's es.c */
+//#define DEBUG_ES
+//#define DEBUG_IDENT
+#define ISALIGNED(x) ((((u32)x)&0x1F)==0)
+
+static u8 su_tmd[0x208] ATTRIBUTE_ALIGN(32);
+static u8 su_tik[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(32);
+int su_id_filled = 0;
+
+
+/* Reads a file from ISFS to an array in memory */
+s32 ISFS_ReadFileToArray (const char *filepath, u8 *filearray, u32 max_size, u32 *file_size) {
+ s32 ret, fd;
+ static fstats filestats ATTRIBUTE_ALIGN(32);
+
+ *file_size = 0;
+ ret = ISFS_Open(filepath, ISFS_OPEN_READ);
+ if (ret <= 0)
+ {
+ //printf("Error! ISFS_Open (ret = %d)\n", ret);
+ return -1;
+ }
+
+ fd = ret;
+
+ ret = ISFS_GetFileStats(fd, &filestats);
+ if (ret < 0)
+ {
+ //printf("Error! ISFS_GetFileStats (ret = %d)\n", ret);
+ return -1;
+ }
+
+ *file_size = filestats.file_length;
+
+ if (*file_size > max_size)
+ {
+ //printf("File is too large! Size: %u Max: %u", *file_size, max_size);
+ return -1;
+ }
+
+ ret = ISFS_Read(fd, filearray, *file_size);
+ *file_size = ret;
+ if (ret < 0)
+ {
+ //printf("Error! ISFS_Read (ret = %d)\n", ret);
+ return -1;
+ }
+ else if (ret != filestats.file_length)
+ {
+ //printf("Error! ISFS_Read Only read: %d\n", ret);
+ return -1;
+ }
+
+ ret = ISFS_Close(fd);
+ if (ret < 0)
+ {
+ //printf("Error! ISFS_Close (ret = %d)\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+void Make_SUID(void){
+ signed_blob *s_tmd, *s_tik;
+ tmd *p_tmd;
+ tik *p_tik;
+
+ memset(su_tmd, 0, sizeof su_tmd);
+ memset(su_tik, 0, sizeof su_tik);
+ s_tmd = (signed_blob*)&su_tmd[0];
+ s_tik = (signed_blob*)&su_tik[0];
+ *s_tmd = *s_tik = 0x10001;
+ p_tmd = (tmd*)SIGNATURE_PAYLOAD(s_tmd);
+ p_tik = (tik*)SIGNATURE_PAYLOAD(s_tik);
+
+
+ strcpy(p_tmd->issuer, "Root-CA00000001-CP00000004");
+ p_tmd->title_id = TITLE_ID(1,2);
+
+ p_tmd->num_contents = 1;
+
+ forge_tmd(s_tmd);
+
+ strcpy(p_tik->issuer, "Root-CA00000001-XS00000003");
+ p_tik->ticketid = 0x000038A45236EE5FLL;
+ p_tik->titleid = TITLE_ID(1,2);
+
+ memset(p_tik->cidx_mask, 0xFF, 0x20);
+ forge_tik(s_tik);
+
+ su_id_filled = 1;
+
+}
+
+s32 Identify(const u8 *certs, u32 certs_size, const u8 *idtmd, u32 idtmd_size, const u8 *idticket, u32 idticket_size) {
+ s32 ret;
+ u32 keyid = 0;
+ ret = ES_Identify((signed_blob*)certs, certs_size, (signed_blob*)idtmd, idtmd_size, (signed_blob*)idticket, idticket_size, &keyid);
+ /*if (ret < 0){
+ switch(ret){
+ case ES_EINVAL:
+ printf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret);
+ break;
+ case ES_EALIGN:
+ printf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret);
+ break;
+ case ES_ENOTINIT:
+ printf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret);
+ break;
+ case ES_ENOMEM:
+ printf("Error! ES_Identify (ret = %d;) No memory!\n", ret);
+ break;
+ default:
+ printf("Error! ES_Identify (ret = %d)\n", ret);
+ break;
+ }
+ }
+ else
+ printf("OK!\n");*/
+ return ret;
+}
+
+
+s32 Identify_SU(void) {
+ if (!su_id_filled)
+ Make_SUID();
+
+ //printf("\nIdentifying as SU...");
+ //fflush(stdout);
+ return Identify(certs_dat, certs_dat_size, su_tmd, sizeof su_tmd, su_tik, sizeof su_tik);
+}
+
+s32 Identify_SysMenu(void) {
+ s32 ret;
+ u32 sysmenu_tmd_size, sysmenu_ticket_size;
+ //static u8 certs[0xA00] ATTRIBUTE_ALIGN(32);
+ static u8 sysmenu_tmd[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32);
+ static u8 sysmenu_ticket[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(32);
+
+ /*printf("\nPulling Certs...");
+ ret = ISFS_ReadFileToArray ("/sys/certs.sys", certs, 0xA00, &certs_size);
+ if (ret < 0) {
+ printf("\tReading Certs failed!\n");
+ return -1;
+ }*/
+
+ //printf("\nPulling Sysmenu TMD...");
+ ret = ISFS_ReadFileToArray ("/title/00000001/00000002/content/title.tmd", sysmenu_tmd, MAX_SIGNED_TMD_SIZE, &sysmenu_tmd_size);
+ if (ret < 0) {
+ //printf("\tReading TMD failed!\n");
+ return -1;
+ }
+
+ //printf("\nPulling Sysmenu Ticket...");
+ ret = ISFS_ReadFileToArray ("/ticket/00000001/00000002.tik", sysmenu_ticket, STD_SIGNED_TIK_SIZE, &sysmenu_ticket_size);
+ if (ret < 0) {
+ //printf("\tReading TMD failed!\n");
+ return -1;
+ }
+
+ //printf("\nIdentifying as SysMenu...");
+ //fflush(stdout);
+ return Identify(certs_dat, certs_dat_size, sysmenu_tmd, sysmenu_tmd_size, sysmenu_ticket, sysmenu_ticket_size);
+}
diff --git a/source/wad/id.h b/source/wad/id.h
new file mode 100644
index 00000000..067c3d08
--- /dev/null
+++ b/source/wad/id.h
@@ -0,0 +1,38 @@
+/*-------------------------------------------------------------
+
+id.h -- ES Identification code
+
+Copyright (C) 2008 tona
+Unless other credit specified
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1.The origin of this software must not be misrepresented; you
+must not claim that you wrote the original software. If you use
+this software in a product, an acknowledgment in the product
+documentation would be appreciated but is not required.
+
+2.Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3.This notice may not be removed or altered from any source
+distribution.
+
+-------------------------------------------------------------*/
+
+#ifndef _ID_H_
+#define _ID_H_
+
+// Identify as the "super user"
+s32 Identify_SU(void);
+
+// Identify as the system menu
+s32 Identify_SysMenu(void);
+
+#endif
diff --git a/source/wad/patchmii_core.c b/source/wad/patchmii_core.c
new file mode 100644
index 00000000..02356956
--- /dev/null
+++ b/source/wad/patchmii_core.c
@@ -0,0 +1,94 @@
+/* patchmii_core -- low-level functions to handle the downloading, patching
+ and installation of updates on the Wii
+
+ Copyright (C) 2008 bushing / hackmii.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "patchmii_core.h"
+#include "sha1.h"
+
+#define ALIGN(a,b) ((((a)+(b)-1)/(b))*(b))
+
+int http_status = 0;
+int tmd_dirty = 0, tik_dirty = 0, temp_ios_slot = 0;
+
+// yeah, yeah, I know.
+signed_blob *s_tmd = NULL, *s_tik = NULL, *s_certs = NULL;
+static u8 tmdbuf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(0x20);
+static u8 tikbuf[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(0x20);
+
+
+void zero_sig(signed_blob *sig) {
+ u8 *sig_ptr = (u8 *)sig;
+ memset(sig_ptr + 4, 0, SIGNATURE_SIZE(sig)-4);
+}
+
+void brute_tmd(tmd *p_tmd) {
+ u16 fill;
+ for(fill=0; fill<65535; fill++) {
+ p_tmd->fill3=fill;
+ sha1 hash;
+ // debug_printf("SHA1(%p, %x, %p)\n", p_tmd, TMD_SIZE(p_tmd), hash);
+ SHA1((u8 *)p_tmd, TMD_SIZE(p_tmd), hash);;
+
+ if (hash[0]==0) {
+ // debug_printf("setting fill3 to %04hx\n", fill);
+ return;
+ }
+ }
+ printf("Unable to fix tmd :(\n");
+ exit(4);
+}
+
+void brute_tik(tik *p_tik) {
+ u16 fill;
+ for(fill=0; fill<65535; fill++) {
+ p_tik->padding=fill;
+ sha1 hash;
+ // debug_printf("SHA1(%p, %x, %p)\n", p_tmd, TMD_SIZE(p_tmd), hash);
+ SHA1((u8 *)p_tik, sizeof(tik), hash);
+
+ if (hash[0]==0) return;
+ }
+ printf("Unable to fix tik :(\n");
+ exit(5);
+}
+
+void forge_tmd(signed_blob *s_tmd) {
+// debug_printf("forging tmd sig");
+ zero_sig(s_tmd);
+ brute_tmd(SIGNATURE_PAYLOAD(s_tmd));
+}
+
+void forge_tik(signed_blob *s_tik) {
+// debug_printf("forging tik sig");
+ zero_sig(s_tik);
+ brute_tik(SIGNATURE_PAYLOAD(s_tik));
+}
+
+
diff --git a/source/wad/patchmii_core.h b/source/wad/patchmii_core.h
new file mode 100644
index 00000000..47488af5
--- /dev/null
+++ b/source/wad/patchmii_core.h
@@ -0,0 +1,63 @@
+#ifndef _PATCHMII_CORE_
+#define _PATCHMII_CORE_
+
+
+//Patchmii functions
+void patchmii_network_init(void);
+// Call with version = 0 to get the latest version
+// Set "patch" if you want to try to patch title contents
+s32 patchmii_install(u32 in_title_h, u32 in_title_l, u32 in_version, u32 out_title_h, u32 out_title_l, u32 out_version, bool patch);
+s32 install_temporary_ios(u32 base_ios, u32 base_ver);
+s32 load_temporary_ios(void);
+s32 cleanup_temporary_ios(void);
+
+//Tools
+void forge_tmd(signed_blob *s_tmd);
+void forge_tik(signed_blob *s_tik);
+
+void spinner(void);
+
+#define TEMP_IOS
+
+// Basic I/O.
+
+static inline u32 read32(u32 addr)
+{
+ u32 x;
+ asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
+ return x;
+}
+
+static inline void write32(u32 addr, u32 x)
+{
+ asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
+}
+
+// USB Gecko.
+
+void usb_flush(int chn);
+int usb_sendbuffer(int chn,const void *buffer,int size);
+
+// Version string.
+
+extern const char version[];
+
+// Debug: blink the tray led.
+
+static inline void blink(void)
+{
+ write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20);
+}
+
+void debug_printf(const char *fmt, ...);
+void hexdump(FILE *fp, void *d, int len);
+void aes_set_key(u8 *key);
+void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len);
+void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len);
+
+#define TRACE(x) debug_printf("%s / %d: %d\n", __FUNCTION__, __LINE__, (x))
+
+#define ISFS_ACCESS_READ 1
+#define ISFS_ACCESS_WRITE 2
+
+#endif
diff --git a/source/wad/sha1.c b/source/wad/sha1.c
new file mode 100644
index 00000000..83a533a7
--- /dev/null
+++ b/source/wad/sha1.c
@@ -0,0 +1,172 @@
+/*
+SHA-1 in C
+By Steve Reid
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd if true. */
+#define SHA1HANDSOFF
+
+#include
+#include
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ unsigned long l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned long i, j;
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) {
+ SHA1_CTX ctx;
+
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, ptr, size);
+ SHA1Final(outbuf, &ctx);
+}
+
diff --git a/source/wad/sha1.h b/source/wad/sha1.h
new file mode 100644
index 00000000..757af1cd
--- /dev/null
+++ b/source/wad/sha1.h
@@ -0,0 +1,12 @@
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf);
diff --git a/source/wad/title.c b/source/wad/title.c
index c36562a1..0fdfa9e9 100644
--- a/source/wad/title.c
+++ b/source/wad/title.c
@@ -8,6 +8,7 @@
#include "utils.h"
#include "../settings/cfg.h"
#include "fatmounter.h"
+#include "id.h"
#define MAX_TITLES 256
@@ -260,6 +261,113 @@ out:
return ret;
}
+s32 Uninstall_RemoveTicket(u64 tid)
+{
+ static tikview viewdata[0x10] ATTRIBUTE_ALIGN(32);
+
+ u32 cnt, views;
+ s32 ret;
+
+/* Get number of ticket views */
+ ret = ES_GetNumTicketViews(tid, &views);
+ if (ret < 0) {
+
+ return ret;
+ }
+
+ if (!views) {
+ //printf(" No tickets found!\n");
+ return 1;
+ } else if (views > 16) {
+ //printf(" Too many ticket views! (views = %d)\n", views);
+ return -1;
+ }
+
+ /* Get ticket views */
+ ret = ES_GetTicketViews(tid, viewdata, views);
+ if (ret < 0) {
+ //printf(" \n\tError! ES_GetTicketViews (ret = %d)\n", ret);
+ return ret;
+ }
+
+ /* Remove tickets */
+ for (cnt = 0; cnt < views; cnt++) {
+ ret = ES_DeleteTicket(&viewdata[cnt]);
+ if (ret < 0) {
+ //printf(" Error! (view = %d, ret = %d)\n", cnt, ret);
+ return ret;
+ }
+ }
+ //printf(" OK!\n");
+
+ return ret;
+}
+
+s32 Uninstall_DeleteTitle(u32 title_u, u32 title_l)
+{
+ s32 ret;
+ char filepath[256];
+ sprintf(filepath, "/title/%08x/%08x", title_u, title_l);
+
+ /* Remove title */
+ ret = ISFS_Delete(filepath);
+ return ret;
+}
+
+s32 Uninstall_DeleteTicket(u32 title_u, u32 title_l)
+{
+ s32 ret;
+
+ char filepath[256];
+ sprintf(filepath, "/ticket/%08x/%08x.tik", title_u, title_l);
+
+ /* Delete ticket */
+ ret = ISFS_Delete(filepath);
+
+ return ret;
+}
+
+//carefull when using this function
+//it will force remove stuff even if something fails
+s32 Uninstall_FromTitle(const u64 tid)
+{
+ s32 contents_ret, tik_ret, title_ret, ret;
+ u32 id = tid & 0xFFFFFFFF, kind = tid >> 32;
+ contents_ret = tik_ret = title_ret = ret = 0;
+
+ if (kind == 1)
+ {
+ // Delete title and ticket at FS level.
+ tik_ret = Uninstall_DeleteTicket(kind, id);
+ title_ret = Uninstall_DeleteTitle(kind, id);
+ contents_ret = title_ret;
+ }
+ else
+ {
+ // Remove title (contents and ticket)
+ tik_ret = Uninstall_RemoveTicket(tid);
+ contents_ret = ES_DeleteTitleContent(tid);
+ title_ret = ES_DeleteTitle(tid);
+
+
+ // Attempt forced uninstall if something fails
+ if (tik_ret < 0 || contents_ret < 0 || title_ret < 0){
+ tik_ret = Uninstall_DeleteTicket(kind, id);
+ title_ret = Uninstall_DeleteTitle(kind, id);
+ contents_ret = title_ret;
+
+ }
+ }
+ if (tik_ret < 0 && contents_ret < 0 && title_ret < 0)
+ ret = -1;
+ else if (tik_ret < 0 || contents_ret < 0 || title_ret < 0)
+ ret = 1;
+ else
+ ret = 0;
+
+ return ret;
+}
+
/*-------------------------------------------------------------
taken from anytitledeleter
@@ -268,104 +376,6 @@ out:
Copyright (C) 2009 MrClick
-------------------------------------------------------------*/
-// Max number of entries in the database
-#define MAX_DB 1024
-
-// Max name length
-#define MAX_LINE 80
-
-// Contains all title ids (e.g.: "HAC")
-static char **__db_i;
-// Contains all title names (e.g.: "Mii Channel")
-static char **__db;
-// Contains the number of entries in the database
-static u32 __db_cnt = 0;
-
-s32 loadDatabase(){
- FILE *fdb;
-
- char dbfile[100];
- snprintf(dbfile,sizeof(dbfile),"SD:/database.txt");
- // Init SD card access, open database file and check if it worked
- //fatInitDefault();
- SDCard_Init();
- fdb = fopen(dbfile, "r");
- if (fdb == NULL)
- return -1;
-
- // Allocate memory for the database
- __db_i = calloc(MAX_DB, sizeof(char*));
- __db = calloc(MAX_DB, sizeof(char*));
-
- // Define the line buffer. Each line in the db file will be stored here first
- char line[MAX_LINE];
- line[sizeof(line)] = 0;
-
- // Generic char buffer and counter variable
- char byte;
- u32 i = 0;
-
- // Read each character from the file
- do {
- byte = fgetc(fdb);
- // In case a line was longer than MAX_LINE
- if (i == -1){
- // Read bytes till a new line is hit
- if (byte == 0x0A)
- i = 0;
- // In case were still good with the line length
- } else {
- // Add the new byte to the line buffer
- line[i] = byte;
- i++;
- // When a new line is hit or MAX_LINE is reached
- if (byte == 0x0A || i == sizeof(line) - 1) {
- // Terminate finished line to create a string
- line[i] = 0;
- // When the line is not a comment or not to short
- if (line[0] != '#' && i > 5){
-
- // Allocate and copy title id to database
- __db_i[__db_cnt] = calloc(4, sizeof(char*));
- memcpy(__db_i[__db_cnt], line, 3);
- __db_i[__db_cnt][3] = 0;
- // Allocate and copy title name to database
- __db[__db_cnt] = calloc(i - 4, sizeof(char*));
- memcpy(__db[__db_cnt], line + 4, i - 4);
- __db[__db_cnt][i - 5] = 0;
-
- // Check that the next line does not overflow the database
- __db_cnt++;
- if (__db_cnt == MAX_DB)
- break;
- }
- // Set routine to ignore all bytes in the line when MAX_LINE is reached
- if (byte == 0x0A) i = 0; else i = -1;
- }
- }
- } while (!feof(fdb));
-
- // Close database file; we are done with it
- fclose(fdb);
-
- return 0;
-}
-
-
-void freeDatabase(){
- u32 i = 0;
- for(; i < __db_cnt; i++){
- free(__db_i[i]);
- free(__db[i]);
- }
- free(__db_i);
- free(__db);
-}
-
-
-s32 getDatabaseCount(){
- return __db_cnt;
-}
s32 __convertWiiString(char *str, u8 *data, u32 cnt){
u32 i = 0;
@@ -385,47 +395,6 @@ s32 __convertWiiString(char *str, u8 *data, u32 cnt){
return 0;
}
-s32 getNameDB(char* name, char* id){
- // Return fixed values for special entries
- if (strncmp(id, "IOS", 3) == 0){
- sprintf(name, "Operating System %s", id);
- return 0;
- }
- if (strncmp(id, "MIOS", 3) == 0){
- sprintf(name, "Gamecube Compatibility Layer");
- return 0;
- }
- if (strncmp(id, "SYSMENU", 3) == 0){
- sprintf(name, "System Menu");
- return 0;
- }
- if (strncmp(id, "BC", 2) == 0){
- sprintf(name, "BC");
- return 0;
- }
-
- // Create an ? just in case the function aborts prematurely
- sprintf(name, "?");
-
- u32 i;
- u8 db_found = 0;
- // Compare each id in the database to the title id
- for (i = 0; i < __db_cnt; i++)
- if (strncmp(id, __db_i[i], 3) == 0){
- db_found = 1;
- break;
- }
-
- if (db_found == 0)
- // Return -1 if no mathcing entry was found
- return -1;
- else {
- // Get name from database once a matching id was found
- sprintf(name, __db[i]);
- return 0;
- }
-}
-
s32 getNameBN(char* name, u64 id){
// Terminate the name string just in case the function exits prematurely
@@ -438,9 +407,9 @@ s32 getNameBN(char* name, u64 id){
// Bring the Wii into the title's userspace
if (ES_SetUID(id) < 0){
// Should that fail repeat after setting permissions to system menu mode
-// Identify_SysMenu();
-// if (ES_SetUID(id) < 0)
-// return -1;
+ Identify_SysMenu();
+ if (ES_SetUID(id) < 0)
+ return -1;
}
// Try to open file
@@ -452,8 +421,8 @@ s32 getNameBN(char* name, u64 id){
// If it fails try to open again after identifying as SU
if (fh == -102){
-// Identify_SU();
-// fh = ISFS_Open(file, ISFS_OPEN_READ);
+ Identify_SU();
+ fh = ISFS_Open(file, ISFS_OPEN_READ);
}
// If the file won't open
else if (fh < 0)
@@ -494,11 +463,21 @@ s32 getNameBN(char* name, u64 id){
}
-s32 getName00(char* name, u64 id){
+s32 getName00(char* name, u64 id, int lang){
+/*
+languages
+0jap
+2eng
+4german
+6french
+8spanish
+10italian
+12dutch
+*/
// Create a string containing the absolute filename
char file[256] __attribute__ ((aligned (32)));
sprintf(file, "/title/%08x/%08x/content/00000000.app", (u32)(id >> 32), (u32)id);
-
+ Identify_SU();
s32 fh = ISFS_Open(file, ISFS_OPEN_READ);
@@ -510,8 +489,8 @@ s32 getName00(char* name, u64 id){
// In case there is some problem with the permission
if (fh == -102){
// Identify as super user
-// Identify_SU();
-// fh = ISFS_Open(file, ISFS_OPEN_READ);
+ Identify_SU();
+ fh = ISFS_Open(file, ISFS_OPEN_READ);
}
else if (fh < 0)
return fh;
@@ -541,12 +520,16 @@ s32 getName00(char* name, u64 id){
free(data);
// Assemble name
- // Only the English name is returned
- // There are 6 other language names in the str array
- sprintf(name, "%s", str[2]);
- if (strlen(str[3]) > 1)
- sprintf(name, "%s (%s)", name, str[3]);
-
+ if(strlen(str[lang]) > 1){
+ sprintf(name, "%s", str[lang]);
+ if (strlen(str[lang+1]) > 1)
+ sprintf(name, "%s (%s)", name, str[lang+1]);
+ }
+ else{
+ sprintf(name, "%s", str[2]);
+ if (strlen(str[3]) > 1)
+ sprintf(name, "%s (%s)", name, str[3]);
+ }
// Job well done
return 2;
}
@@ -575,35 +558,6 @@ s32 printContent(u64 tid){
}
-s32 getTitle_Name(char* name, u64 id, char *tid){
- char buf[256] __attribute__ ((aligned (32)));
-
- s32 r = -1;
- // Determine the title's name database/banner/00000000.app
- r = getNameDB(buf, tid);
- if (r < 0)
- r = getNameBN(buf, id);
- if (r < 0)
- r = getName00(buf, id);
-
- switch (r){
- // In case a name was found in the database
- case 0: sprintf(name, "%s", buf);
- break;
- // In case a name was found in the banner.bin
- case 1: sprintf(name, "*%s*", buf);
- break;
- // In case a name was found in the 00000000.app
- case 2: sprintf(name, "+%s+", buf);
- break;
- // In case no proper name was found return a ?
- default: sprintf(name, "Unknown Title");
- break;
- }
-
- return 0;
-}
-
char *titleText(u32 kind, u32 title){
static char text[10];
@@ -684,7 +638,7 @@ s32 getTitles_TypeCount(u32 type, u32 *count) {
upper = __title_list[i] >> 32;
lower = __title_list[i] & 0xFFFFFFFF;
if((upper == type)&&
- ((lower !=0x48414741)&&//this filters out haga,haaa, hafa. dupe foctory channels that don't load
+ ((lower !=0x48414741)&&//this filters out haga,haaa, hafa. dupe factory channels that don't load
(lower !=0x48414141)&&//since we dont care about apps that dont load for what we are doing
(lower !=0x48414641)))
type_count++;
@@ -721,3 +675,6 @@ s32 getTitles_Type(u32 type, u32 *titles, u32 count) {
}
+
+
+
diff --git a/source/wad/title.h b/source/wad/title.h
index 03a68af2..3eb76a4b 100644
--- a/source/wad/title.h
+++ b/source/wad/title.h
@@ -39,26 +39,11 @@ s32 Title_GetSysVersion(u64, u64 *);
s32 Title_GetSize(u64, u32 *);
s32 Title_GetIOSVersions(u8 **, u32 *);
-// Load the database from SD card
-s32 loadDatabase();
-
-// Free the database on exit
-void freeDatabase();
-
-// Get the number of entries in the database
-s32 getDatabaseCount();
-
-// Get the name of a title
-s32 getTitle_Name(char *name, u64 id, char *tid);
-
-// Get the name of a title from the database located on the SD card
-s32 getNameDB(char *name, char* id);
-
// Get the name of a title from its banner.bin in NAND
s32 getNameBN(char *name, u64 id);
// Get the name of a title from its 00000000.app in NAND
-s32 getName00(char *name, u64 id);
+s32 getName00(char *name, u64 id, int lang = 2);
// Get string representation of lower title id
char *titleText(u32 kind, u32 title);
@@ -71,6 +56,11 @@ s32 getTitles_TypeCount(u32 type, u32 *count);
// Get the list of titles of this type
s32 getTitles_Type(u32 type, u32 *titles, u32 count);
+
+//returns a name for a title
+char *__getTitleName(u64 titleid, int language);
+
+s32 Uninstall_FromTitle(const u64 tid);
#ifdef __cplusplus
}
diff --git a/source/xml/xml.c b/source/xml/xml.c
index 51f38710..da6cb8dc 100644
--- a/source/xml/xml.c
+++ b/source/xml/xml.c
@@ -331,7 +331,7 @@ void LoadTitlesFromXML(char *langtxt, bool forcejptoen)
strcpy(title_text,title_text_EN);
}
- snprintf(id_text, 5, "%s",id_text);
+ snprintf(id_text, 7, "%s",id_text);
title_set(id_text, title_text);
}
}