mirror of
https://github.com/wiiu-env/haxchi.git
synced 2024-06-25 18:56:07 +02:00
818 lines
22 KiB
C
818 lines
22 KiB
C
/*
|
|
* Copyright (C) 2016-2017 FIX94
|
|
*
|
|
* This software may be modified and distributed under the terms
|
|
* of the MIT license. See the LICENSE file for details.
|
|
*/
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <iosuhax.h>
|
|
#include <coreinit/mcp.h>
|
|
#include <vpad/input.h>
|
|
|
|
#include <whb/proc.h>
|
|
#include <whb/log.h>
|
|
#include <whb/log_console.h>
|
|
|
|
|
|
#include <coreinit/foreground.h>
|
|
#include <coreinit/systeminfo.h>
|
|
#include <proc_ui/procui.h>
|
|
#include <sysapp/launch.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/tree.h>
|
|
#include <libxml/xpath.h>
|
|
#include "main.h"
|
|
#include "gameList.h"
|
|
#include "memory.h"
|
|
|
|
|
|
static const char *sdCardVolPath = "/vol/storage_sdcard_new";
|
|
#ifdef CB
|
|
static const char *systemXmlPath = "/vol/system/config/system.xml";
|
|
static const char *systemXmlPath2 = "/vol/system/config/system_new.xml";
|
|
static const char *syshaxXmlPath = "/vol/system/config/syshax.xml";
|
|
#endif
|
|
//just to be able to call async
|
|
void someFunc(void *arg)
|
|
{
|
|
(void)arg;
|
|
}
|
|
|
|
extern void OSForceFullRelaunch(void);
|
|
extern unsigned long long(*_SYSGetSystemApplicationTitleId)(int sysApp);
|
|
|
|
|
|
void println_noflip(int line, const char *msg)
|
|
{
|
|
WHBLogPrintf(msg);
|
|
WHBLogConsoleDraw();
|
|
}
|
|
|
|
void println(int line, const char *msg)
|
|
{
|
|
WHBLogPrintf(msg);
|
|
WHBLogConsoleDraw();
|
|
}
|
|
|
|
typedef struct _parsedList_t {
|
|
uint32_t tid;
|
|
char name[64];
|
|
char path[64];
|
|
uint8_t *romPtr;
|
|
uint32_t romSize;
|
|
} parsedList_t;
|
|
|
|
int fsa_read(int fsa_fd, int fd, void *buf, int len)
|
|
{
|
|
int done = 0;
|
|
uint8_t *buf_uint8_t = (uint8_t*)buf;
|
|
while(done < len)
|
|
{
|
|
size_t read_size = len - done;
|
|
int result = IOSUHAX_FSA_ReadFile(fsa_fd, buf_uint8_t + done, 0x01, read_size, fd, 0);
|
|
if(result < 0)
|
|
return result;
|
|
else
|
|
done += result;
|
|
}
|
|
return done;
|
|
}
|
|
|
|
int fsa_write(int fsa_fd, int fd, void *buf, int len)
|
|
{
|
|
int done = 0;
|
|
uint8_t *buf_uint8_t = (uint8_t*)buf;
|
|
while(done < len)
|
|
{
|
|
size_t write_size = len - done;
|
|
int result = IOSUHAX_FSA_WriteFile(fsa_fd, buf_uint8_t + done, 0x01, write_size, fd, 0);
|
|
if(result < 0)
|
|
return result;
|
|
else
|
|
done += result;
|
|
}
|
|
return done;
|
|
}
|
|
|
|
int availSort(const void *c1, const void *c2)
|
|
{
|
|
return strcmp(((parsedList_t*)c1)->name,((parsedList_t*)c2)->name);
|
|
}
|
|
|
|
void printhdr_noflip()
|
|
{
|
|
#ifdef CB
|
|
println_noflip(0,"CBHC v1.6 by FIX94");
|
|
#else
|
|
println_noflip(0,"Haxchi v2.5u2 by FIX94");
|
|
#endif
|
|
println_noflip(1,"Credits to smea, plutoo, yellows8, naehrwert, derrek and dimok");
|
|
}
|
|
|
|
static uint32_t
|
|
procSaveCallback(void *context) {
|
|
OSSavesDone_ReadyToRelease();
|
|
return 0;
|
|
}
|
|
|
|
int cleanupAndExitToHBL(){
|
|
memoryRelease();
|
|
WHBLogConsoleFree();
|
|
WHBProcShutdown();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
|
|
OSEnableHomeButtonMenu(FALSE);
|
|
WHBProcInit();
|
|
WHBLogConsoleInit();
|
|
|
|
VPADInit();
|
|
memoryInitialize();
|
|
|
|
int mcp_handle = MCP_Open();
|
|
int count = MCP_TitleCount(mcp_handle);
|
|
int listSize = count*sizeof(MCPTitleListType);
|
|
MCPTitleListType *tList = (MCPTitleListType*)memalign(32, listSize); //cant be in MEMBucket
|
|
memset(tList, 0, listSize);
|
|
uint32_t recievedCount = count;
|
|
MCP_TitleList(mcp_handle, &recievedCount, tList, listSize);
|
|
MCP_Close(mcp_handle);
|
|
|
|
int gAvailCnt = 0;
|
|
parsedList_t *gAvail = (parsedList_t*)MEMBucket_alloc(recievedCount*sizeof(parsedList_t), 4);
|
|
memset(gAvail, 0, recievedCount*sizeof(parsedList_t));
|
|
|
|
int i, j;
|
|
for(i = 0; i < recievedCount; i++)
|
|
{
|
|
MCPTitleListType cListElm = tList[i];
|
|
if(memcmp(cListElm.indexedDevice,"mlc",4) != 0 || ((cListElm.titleId & 0xFFFFFFFF00000000L) != 0x0005000000000000L))
|
|
continue;
|
|
for(j = 0; j < GameListSize; j++)
|
|
{
|
|
if((cListElm.titleId & 0x00000000FFFFFFFFL) == GameList[j].tid)
|
|
{
|
|
gAvail[gAvailCnt].tid = GameList[j].tid;
|
|
memcpy(gAvail[gAvailCnt].name, GameList[j].name, 64);
|
|
memcpy(gAvail[gAvailCnt].path, cListElm.path, 64);
|
|
gAvail[gAvailCnt].romPtr = GameList[j].romPtr;
|
|
gAvail[gAvailCnt].romSize = *(GameList[j].romSizePtr);
|
|
gAvailCnt++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int vpadError = -1;
|
|
VPADStatus vpad;
|
|
|
|
if(gAvailCnt == 0)
|
|
{
|
|
printhdr_noflip();
|
|
println_noflip(2,"No games found on NAND! Make sure that you have your DS VC");
|
|
println_noflip(3,"game installed on NAND and have all of your USB Devices");
|
|
println_noflip(4,"disconnected while installing Haxchi as it can lead to issues.");
|
|
println_noflip(5,"Press any button to return to Homebrew Launcher.");
|
|
|
|
while(1)
|
|
{
|
|
usleep(25000);
|
|
VPADRead(0, &vpad, 1, &vpadError);
|
|
if(vpadError != 0)
|
|
continue;
|
|
if(vpad.trigger | vpad.hold)
|
|
break;
|
|
}
|
|
return cleanupAndExitToHBL();
|
|
}
|
|
|
|
qsort(gAvail,gAvailCnt,sizeof(parsedList_t),availSort);
|
|
|
|
uint32_t redraw = 1;
|
|
int32_t PosX = 0;
|
|
int32_t ScrollX = 0;
|
|
|
|
int32_t ListMax = gAvailCnt;
|
|
if( ListMax > 13 )
|
|
ListMax = 13;
|
|
|
|
uint32_t UpHeld = 0, triggerHeld = 0;
|
|
while(1)
|
|
{
|
|
usleep(25000);
|
|
VPADRead(0, &vpad, 1, &vpadError);
|
|
if(vpadError != 0)
|
|
continue;
|
|
|
|
if((vpad.trigger | vpad.hold) & VPAD_BUTTON_HOME)
|
|
{
|
|
|
|
return cleanupAndExitToHBL();
|
|
}
|
|
if( vpad.hold & VPAD_BUTTON_DOWN)
|
|
{
|
|
if(triggerHeld == 0 || triggerHeld > 10)
|
|
{
|
|
if( PosX + 1 >= ListMax )
|
|
{
|
|
if( PosX + 1 + ScrollX < gAvailCnt)
|
|
ScrollX++;
|
|
else {
|
|
PosX = 0;
|
|
ScrollX = 0;
|
|
}
|
|
} else {
|
|
PosX++;
|
|
}
|
|
redraw = 1;
|
|
}
|
|
triggerHeld++;
|
|
}
|
|
else
|
|
triggerHeld = 0;
|
|
|
|
if( vpad.hold & VPAD_BUTTON_UP )
|
|
{
|
|
if(UpHeld == 0 || UpHeld > 10)
|
|
{
|
|
if( PosX <= 0 )
|
|
{
|
|
if( ScrollX > 0 )
|
|
ScrollX--;
|
|
else {
|
|
PosX = ListMax - 1;
|
|
ScrollX = gAvailCnt - ListMax;
|
|
}
|
|
} else {
|
|
PosX--;
|
|
}
|
|
redraw = 1;
|
|
}
|
|
UpHeld++;
|
|
}
|
|
else
|
|
UpHeld = 0;
|
|
|
|
if( vpad.trigger & VPAD_BUTTON_A )
|
|
break;
|
|
|
|
if( redraw )
|
|
{
|
|
|
|
printhdr_noflip();
|
|
println_noflip(2,"Please select the game for the Installation from the list below.");
|
|
// Starting position.
|
|
int gamelist_y = 4;
|
|
for (i = 0; i < ListMax; ++i, gamelist_y++)
|
|
{
|
|
const parsedList_t *cur_gi = &gAvail[i+ScrollX];
|
|
char printStr[64];
|
|
sprintf(printStr,"%c %s", i == PosX ? '>' : ' ', cur_gi->name);
|
|
println_noflip(gamelist_y, printStr);
|
|
}
|
|
redraw = 0;
|
|
}
|
|
}
|
|
#ifdef CB
|
|
int action = 0;
|
|
#endif
|
|
const parsedList_t *SelectedGame = &gAvail[PosX + ScrollX];
|
|
println_noflip(2,"You have selected the following game:");
|
|
println_noflip(3,SelectedGame->name);
|
|
#ifdef CB
|
|
println_noflip(4,"Press A to install CBHC, B to remove coldboothax, HOME to Exit.");
|
|
println_noflip(5,"WARNING, INSTALLING CBHC CAN POTENTIALLY BRICK YOUR SYSTEM!");
|
|
println_noflip(6,"NEVER UNINSTALL OR MOVE THE SELECTED GAME OR YOUR WIIU IS DEAD!");
|
|
#else
|
|
println_noflip(4,"This will install Haxchi. To remove it you have to delete and");
|
|
println_noflip(5,"re-install the game. If you are sure press A, else press HOME.");
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
usleep(25000);
|
|
VPADRead(0, &vpad, 1, &vpadError);
|
|
if(vpadError != 0)
|
|
continue;
|
|
//user aborted
|
|
if((vpad.trigger | vpad.hold) & VPAD_BUTTON_HOME)
|
|
{
|
|
return cleanupAndExitToHBL();
|
|
}
|
|
//lets go!
|
|
if(vpad.trigger & VPAD_BUTTON_A)
|
|
break;
|
|
#ifdef CB
|
|
if(vpad.trigger & VPAD_BUTTON_B)
|
|
{
|
|
action = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CB
|
|
unsigned long long sysmenuIdUll = _SYSGetSystemApplicationTitleId(0);
|
|
char sysmenuId[20];
|
|
memset(sysmenuId, 0, 20);
|
|
sprintf(sysmenuId, "%08x%08x", (uint32_t)((sysmenuIdUll>>32)&0xFFFFFFFF),(uint32_t)(sysmenuIdUll&0xFFFFFFFF));
|
|
char new_title_id[20];
|
|
memset(new_title_id, 0, 20);
|
|
sprintf(new_title_id, "00050000%08x", SelectedGame->tid);
|
|
int line = 7;
|
|
#else
|
|
int line = 6;
|
|
#endif
|
|
|
|
int fsaFd = -1;
|
|
int sdMounted = 0;
|
|
int sdFd = -1, mlcFd = -1, slcFd = -1;
|
|
|
|
//open up iosuhax
|
|
int res = IOSUHAX_Open(NULL);
|
|
if(res < 0)
|
|
{
|
|
println(line++,"IOSUHAX_Open failed");
|
|
goto prgEnd;
|
|
}
|
|
|
|
//mount with full permissions
|
|
fsaFd = IOSUHAX_FSA_Open();
|
|
if(fsaFd < 0)
|
|
{
|
|
println(line++,"FSA could not be opened!");
|
|
goto prgEnd;
|
|
}
|
|
#ifdef CB
|
|
if(action == 1)
|
|
{
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "rb", &slcFd) >= 0)
|
|
{
|
|
//read in system xml file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats);
|
|
size_t sysXmlSize = stats.size;
|
|
char *sysXmlBuf = MEMBucket_alloc(sysXmlSize+1,4);
|
|
memset(sysXmlBuf, 0, sysXmlSize+1);
|
|
fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "system.xml", "utf-8", 0);
|
|
//verify title id
|
|
int idFound = 0, idCorrect = 0;
|
|
xmlNode *root_element = xmlDocGetRootElement(doc);
|
|
xmlNode *cur_node = NULL;
|
|
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
|
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
if(memcmp(cur_node->name, "default_title_id", 17) == 0)
|
|
{
|
|
if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue;
|
|
if(memcmp(new_title_id, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++;
|
|
idFound++;
|
|
}
|
|
}
|
|
}
|
|
xmlFreeDoc(doc);
|
|
MEMBucket_free(sysXmlBuf);
|
|
if(idFound != 1)
|
|
println(line++,"default_title_id missing!");
|
|
else if(idCorrect != 1)
|
|
println(line++,"default_title_id not set to selected DS VC!");
|
|
else
|
|
{
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "rb", &slcFd) >= 0)
|
|
{
|
|
//read in system xml file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats);
|
|
size_t sysXmlSize = stats.size;
|
|
sysXmlBuf = MEMBucket_alloc(sysXmlSize+1,4);
|
|
memset(sysXmlBuf, 0, sysXmlSize+1);
|
|
fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "syshax.xml", "utf-8", 0);
|
|
//verify title id
|
|
int idFound = 0, idCorrect = 0;
|
|
xmlNode *root_element = xmlDocGetRootElement(doc);
|
|
xmlNode *cur_node = NULL;
|
|
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
|
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
if(memcmp(cur_node->name, "default_title_id", 17) == 0)
|
|
{
|
|
if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue;
|
|
if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++;
|
|
idFound++;
|
|
}
|
|
}
|
|
}
|
|
xmlFreeDoc(doc);
|
|
if(idFound != 1)
|
|
println(line++,"default_title_id missing!");
|
|
else if(idCorrect != 1)
|
|
println(line++,"default_title_id not set to System Menu!");
|
|
else
|
|
{
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "wb", &slcFd) >= 0)
|
|
{
|
|
println(line++,"Restoring system.xml...");
|
|
fsa_write(fsaFd, slcFd, sysXmlBuf, sysXmlSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
println(line++,"Removed coldboothax!");
|
|
}
|
|
}
|
|
MEMBucket_free(sysXmlBuf);
|
|
}
|
|
else
|
|
println(line++,"syshax.xml backup not found, aborting!");
|
|
}
|
|
}
|
|
goto prgEnd;
|
|
}
|
|
#endif
|
|
int ret = IOSUHAX_FSA_Mount(fsaFd, "/dev/sdcard01", sdCardVolPath, 2, (void*)0, 0);
|
|
if(ret < 0)
|
|
{
|
|
println(line++,"Failed to mount SD!");
|
|
goto prgEnd;
|
|
}
|
|
else
|
|
sdMounted = 1;
|
|
char path[256];
|
|
sprintf(path,"%s/content/0010/rom.zip",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "rb", &mlcFd) < 0)
|
|
{
|
|
println(line++,"No already existing rom.zip found in the game!");
|
|
println(line++,"Make sure to re-install your DS title and try again.");
|
|
goto prgEnd;
|
|
}
|
|
else
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing rom.zip...");
|
|
fsa_write(fsaFd, mlcFd, SelectedGame->romPtr, SelectedGame->romSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
|
|
char sdHaxchiPath[256];
|
|
#ifdef CB
|
|
sprintf(sdHaxchiPath,"%s/cbhc",sdCardVolPath);
|
|
#else
|
|
sprintf(sdHaxchiPath,"%s/haxchi",sdCardVolPath);
|
|
#endif
|
|
char sdPath[256];
|
|
|
|
#ifndef CB
|
|
sprintf(sdPath,"%s/config.txt",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t cfgSize = stats.size;
|
|
uint8_t *cfgBuf = MEMBucket_alloc(cfgSize,4);
|
|
fsa_read(fsaFd, sdFd, cfgBuf, cfgSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
//write to nand
|
|
sprintf(path,"%s/content/config.txt",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing config.txt...");
|
|
fsa_write(fsaFd, mlcFd, cfgBuf, cfgSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
//make it readable by game
|
|
IOSUHAX_FSA_ChangeMode(fsaFd, path, 0x644);
|
|
}
|
|
MEMBucket_free(cfgBuf);
|
|
}
|
|
#endif
|
|
|
|
sprintf(sdPath,"%s/title.txt",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t titleSize = stats.size;
|
|
xmlChar *titleBuf = MEMBucket_alloc(titleSize+1,4);
|
|
memset(titleBuf, 0, titleSize+1);
|
|
fsa_read(fsaFd, sdFd, titleBuf, titleSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
sprintf(path,"%s/meta/meta.xml",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "rb", &mlcFd) >= 0)
|
|
{
|
|
IOSUHAX_FSA_StatFile(fsaFd, mlcFd, &stats);
|
|
size_t metaSize = stats.size;
|
|
char *metaBuf = MEMBucket_alloc(metaSize,4);
|
|
fsa_read(fsaFd, mlcFd, metaBuf, metaSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
//parse doc
|
|
xmlDocPtr doc = xmlReadMemory(metaBuf, metaSize, "meta.xml", "utf-8", 0);
|
|
//change title
|
|
xmlNode *root_element = xmlDocGetRootElement(doc);
|
|
xmlNode *cur_node = NULL;
|
|
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
|
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
if(memcmp(cur_node->name, "longname_", 9) == 0 || memcmp(cur_node->name, "shortname_", 10) == 0)
|
|
{
|
|
if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue;
|
|
xmlNodeSetContent(cur_node, titleBuf);
|
|
}
|
|
}
|
|
}
|
|
//back to xml
|
|
xmlChar *newXml = NULL;
|
|
int newSize = 0;
|
|
xmlSaveNoEmptyTags = 1; //keeps original style
|
|
xmlDocDumpFormatMemoryEnc(doc, &newXml, &newSize, "utf-8", 0);
|
|
xmlFreeDoc(doc);
|
|
if(newXml != NULL && newSize > 0)
|
|
{
|
|
//libxml2 adds in extra \n at the end
|
|
if(newXml[newSize-1] == '\n' && metaBuf[metaSize-1] != '\n')
|
|
{
|
|
newXml[newSize-1] = '\0';
|
|
newSize--;
|
|
}
|
|
//write back to nand
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Changing game title...");
|
|
//UTF-8 BOM
|
|
char bom[3] = { 0xEF, 0xBB, 0xBF };
|
|
if(memcmp(newXml, bom, 3) != 0 && memcmp(metaBuf, bom, 3) == 0)
|
|
fsa_write(fsaFd, mlcFd, bom, 0x03);
|
|
fsa_write(fsaFd, mlcFd, newXml, newSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
free(newXml);
|
|
}
|
|
MEMBucket_free(metaBuf);
|
|
}
|
|
MEMBucket_free(titleBuf);
|
|
}
|
|
|
|
sprintf(sdPath,"%s/bootDrcTex.tga",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t bootDrcTexSize = stats.size;
|
|
uint8_t *bootDrcTex = MEMBucket_alloc(bootDrcTexSize,4);
|
|
fsa_read(fsaFd, sdFd, bootDrcTex, bootDrcTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
//write to nand
|
|
sprintf(path,"%s/meta/bootDrcTex.tga",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing bootDrcTex.tga...");
|
|
fsa_write(fsaFd, mlcFd, bootDrcTex, bootDrcTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
MEMBucket_free(bootDrcTex);
|
|
}
|
|
|
|
sprintf(sdPath,"%s/bootTvTex.tga",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t bootTvTexSize = stats.size;
|
|
uint8_t *bootTvTex = MEMBucket_alloc(bootTvTexSize,4);
|
|
fsa_read(fsaFd, sdFd, bootTvTex, bootTvTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
//write to nand
|
|
sprintf(path,"%s/meta/bootTvTex.tga",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing bootTvTex.tga...");
|
|
fsa_write(fsaFd, mlcFd, bootTvTex, bootTvTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
MEMBucket_free(bootTvTex);
|
|
}
|
|
|
|
sprintf(sdPath,"%s/iconTex.tga",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t iconTexSize = stats.size;
|
|
uint8_t *iconTex = MEMBucket_alloc(iconTexSize,4);
|
|
fsa_read(fsaFd, sdFd, iconTex, iconTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
//write to nand
|
|
sprintf(path,"%s/meta/iconTex.tga",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing iconTex.tga...");
|
|
fsa_write(fsaFd, mlcFd, iconTex, iconTexSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
MEMBucket_free(iconTex);
|
|
}
|
|
|
|
sprintf(sdPath,"%s/bootSound.btsnd",sdHaxchiPath);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0)
|
|
{
|
|
//read in sd file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, sdFd, &stats);
|
|
size_t bootSoundSize = stats.size;
|
|
uint8_t *bootSound = MEMBucket_alloc(bootSoundSize,4);
|
|
fsa_read(fsaFd, sdFd, bootSound, bootSoundSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
sdFd = -1;
|
|
//write to nand
|
|
sprintf(path,"%s/meta/bootSound.btsnd",SelectedGame->path);
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, path, "wb", &mlcFd) >= 0)
|
|
{
|
|
println(line++,"Writing bootSound.btsnd...");
|
|
fsa_write(fsaFd, mlcFd, bootSound, bootSoundSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
mlcFd = -1;
|
|
}
|
|
MEMBucket_free(bootSound);
|
|
}
|
|
|
|
#ifdef CB
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "rb", &slcFd) >= 0)
|
|
{
|
|
//read in system xml file
|
|
fileStat_s stats;
|
|
IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats);
|
|
size_t sysXmlSize = stats.size;
|
|
char *sysXmlBuf = MEMBucket_alloc(sysXmlSize+1,4);
|
|
memset(sysXmlBuf, 0, sysXmlSize+1);
|
|
fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "system.xml", "utf-8", 0);
|
|
//change default title id
|
|
int idFound = 0, idCorrect = 0;
|
|
xmlNode *root_element = xmlDocGetRootElement(doc);
|
|
xmlNode *cur_node = NULL;
|
|
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
|
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
if(memcmp(cur_node->name, "default_title_id", 17) == 0)
|
|
{
|
|
if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue;
|
|
if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++;
|
|
idFound++;
|
|
}
|
|
}
|
|
}
|
|
if(idFound != 1)
|
|
println(line++,"default_title_id missing!");
|
|
else if(idCorrect != 1)
|
|
println(line++,"default_title_id not set to System Menu!");
|
|
else
|
|
{
|
|
int xmlBackedUp = 0;
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "rb", &slcFd) < 0)
|
|
{
|
|
//write syshax.xml
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "wb", &slcFd) >= 0)
|
|
{
|
|
println(line++,"Writing syshax.xml...");
|
|
fsa_write(fsaFd, slcFd, sysXmlBuf, sysXmlSize);
|
|
xmlBackedUp = 1;
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
println(line++,"syshax.xml already found, skipping...");
|
|
xmlBackedUp = 1;
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
}
|
|
if(xmlBackedUp == 0)
|
|
println(line++,"Failed to back up system.xml!");
|
|
else
|
|
{
|
|
idFound = 0, idCorrect = 0;
|
|
root_element = xmlDocGetRootElement(doc);
|
|
cur_node = NULL;
|
|
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
|
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
if(memcmp(cur_node->name, "default_title_id", 17) == 0)
|
|
{
|
|
if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue;
|
|
if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0)
|
|
{
|
|
xmlNodeSetContent(cur_node, (xmlChar*)new_title_id);
|
|
idCorrect++;
|
|
}
|
|
idFound++;
|
|
}
|
|
}
|
|
}
|
|
if(idFound != 1)
|
|
println(line++,"default_title_id missing!");
|
|
else if(idCorrect != 1)
|
|
println(line++,"default_title_id not set to System Menu!");
|
|
else
|
|
{
|
|
//back to xml
|
|
xmlChar *newXml = NULL;
|
|
int newSize = 0;
|
|
xmlSaveNoEmptyTags = 0; //yep, different from meta.xml style
|
|
xmlDocDumpFormatMemoryEnc(doc, &newXml, &newSize, "utf-8", 0);
|
|
xmlFreeDoc(doc);
|
|
if(newXml != NULL && newSize > 0)
|
|
{
|
|
//libxml2 adds in extra \n at the end
|
|
if(newXml[newSize-1] == '\n' && sysXmlBuf[sysXmlSize-1] != '\n')
|
|
{
|
|
newXml[newSize-1] = '\0';
|
|
newSize--;
|
|
}
|
|
//write back to nand
|
|
if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath2, "wb", &slcFd) >= 0)
|
|
{
|
|
println(line++,"Writing system.xml...");
|
|
//UTF-8 BOM
|
|
char bom[3] = { 0xEF, 0xBB, 0xBF };
|
|
if(memcmp(newXml, bom, 3) != 0 && memcmp(sysXmlBuf, bom, 3) == 0)
|
|
fsa_write(fsaFd, slcFd, bom, 0x03);
|
|
fsa_write(fsaFd, slcFd, newXml, newSize);
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
slcFd = -1;
|
|
}
|
|
free(newXml);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MEMBucket_free(sysXmlBuf);
|
|
}
|
|
println(line++,"Done installing CBHC!");
|
|
#else
|
|
println(line++,"Done installing Haxchi!");
|
|
#endif
|
|
|
|
WHBLogPrintf("Success");
|
|
WHBLogConsoleDraw();
|
|
|
|
prgEnd:
|
|
if(tList) //cant be in MEMBucket
|
|
free(tList);
|
|
//close trigger everything fsa related
|
|
if(fsaFd >= 0)
|
|
{
|
|
if(slcFd >= 0)
|
|
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
|
|
if(mlcFd >= 0)
|
|
IOSUHAX_FSA_CloseFile(fsaFd, mlcFd);
|
|
if(sdFd >= 0)
|
|
IOSUHAX_FSA_CloseFile(fsaFd, sdFd);
|
|
if(sdMounted)
|
|
IOSUHAX_FSA_Unmount(fsaFd, sdCardVolPath, 2);
|
|
|
|
if(IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0)
|
|
println(line++, "Flushed NAND Cache!");
|
|
|
|
IOSUHAX_FSA_Close(fsaFd);
|
|
}
|
|
|
|
IOSUHAX_Close();
|
|
|
|
sleep(5);
|
|
|
|
OSForceFullRelaunch();
|
|
ProcUIShutdown();
|
|
|
|
memoryRelease();
|
|
WHBLogConsoleFree();
|
|
SYSRelaunchTitle(0, NULL);
|
|
WHBProcShutdown();
|
|
|
|
return 0;
|
|
}
|