mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-01 00:55:06 +01:00
-added a wad installer to install wiiware and virtual console to your emu nand
-updated english.ini
This commit is contained in:
parent
791a2dc41b
commit
c77ede571f
@ -52,7 +52,8 @@ typedef struct _namelist
|
|||||||
typedef struct _uid
|
typedef struct _uid
|
||||||
{
|
{
|
||||||
u64 TitleID;
|
u64 TitleID;
|
||||||
u32 unused;
|
u16 padding;
|
||||||
|
u16 uid;
|
||||||
} ATTRIBUTE_PACKED uid;
|
} ATTRIBUTE_PACKED uid;
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -85,6 +86,7 @@ public:
|
|||||||
u8 *GetTMD(u64 title, u32 *size);
|
u8 *GetTMD(u64 title, u32 *size);
|
||||||
u8 *GetEmuFile(const char *path, u32 *size, s32 len = -1);
|
u8 *GetEmuFile(const char *path, u32 *size, s32 len = -1);
|
||||||
void SetPaths(const char *emuPath, const char *currentPart);
|
void SetPaths(const char *emuPath, const char *currentPart);
|
||||||
|
const char *GetPath(void) { return FullNANDPath; };
|
||||||
|
|
||||||
void CreatePath(const char *path, ...);
|
void CreatePath(const char *path, ...);
|
||||||
void CreateTitleTMD(dir_discHdr *hdr);
|
void CreateTitleTMD(dir_discHdr *hdr);
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "gecko/gecko.hpp"
|
||||||
|
#include "loader/utils.h"
|
||||||
#define u8 unsigned char /* 8 bits */
|
#define u8 unsigned char /* 8 bits */
|
||||||
#define u32 unsigned long /* 32 bits */
|
#define u32 unsigned long /* 32 bits */
|
||||||
#define u64 unsigned long long
|
#define u64 unsigned long long
|
||||||
@ -364,16 +365,16 @@ void aes_set_key(u8 *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CBC mode decryption
|
// CBC mode decryption
|
||||||
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len)
|
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len)
|
||||||
{
|
{
|
||||||
u8 block[16];
|
u8 block[16];
|
||||||
unsigned int blockno = 0, i;
|
u32 blockno = 0, i;
|
||||||
|
|
||||||
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
||||||
|
|
||||||
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++)
|
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++)
|
||||||
{
|
{
|
||||||
unsigned int fraction;
|
u32 fraction;
|
||||||
if (blockno == (len / sizeof(block))) // last block
|
if (blockno == (len / sizeof(block))) // last block
|
||||||
{
|
{
|
||||||
fraction = len % sizeof(block);
|
fraction = len % sizeof(block);
|
||||||
@ -398,16 +399,16 @@ void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CBC mode encryption
|
// CBC mode encryption
|
||||||
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len)
|
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len)
|
||||||
{
|
{
|
||||||
u8 block[16];
|
u8 block[16];
|
||||||
unsigned int blockno = 0, i;
|
u32 blockno = 0, i;
|
||||||
|
|
||||||
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
||||||
|
|
||||||
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++)
|
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++)
|
||||||
{
|
{
|
||||||
unsigned int fraction;
|
u32 fraction;
|
||||||
if (blockno == (len / sizeof(block))) // last block
|
if (blockno == (len / sizeof(block))) // last block
|
||||||
{
|
{
|
||||||
fraction = len % sizeof(block);
|
fraction = len % sizeof(block);
|
||||||
@ -430,3 +431,15 @@ void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CBC mode decryption
|
||||||
|
#define WAD_BUF 0x10000
|
||||||
|
|
||||||
|
void aes_decrypt_partial(u8 *inbuf, u8 *outbuf, u8 block[16], u8 *ctext_ptr, u32 tmp_blockno)
|
||||||
|
{
|
||||||
|
memcpy(block, inbuf + tmp_blockno * 16, 16);
|
||||||
|
decrypt((char*)block);
|
||||||
|
u32 i;
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
outbuf[tmp_blockno * 16 + i] = ctext_ptr[i] ^ block[i];
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "wiidisc.h"
|
#include "wiidisc.h"
|
||||||
|
|
||||||
void aes_set_key(u8 *key);
|
void aes_set_key(u8 *key);
|
||||||
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len);
|
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len);
|
||||||
|
|
||||||
int wd_last_error = 0;
|
int wd_last_error = 0;
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ int wd_get_last_error(void)
|
|||||||
return wd_last_error;
|
return wd_last_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _decrypt_title_key(u8 *tik, u8 *title_key)
|
void decrypt_title_key(u8 *tik, u8 *title_key)
|
||||||
{
|
{
|
||||||
u8 common_key[16] = {
|
u8 common_key[16] = {
|
||||||
0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4,
|
0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4,
|
||||||
@ -251,7 +251,7 @@ static void do_partition(wiidisc_t*d)
|
|||||||
wbfs_fatal("malloc cert\n");
|
wbfs_fatal("malloc cert\n");
|
||||||
partition_raw_read(d, cert_offset, cert, cert_size);
|
partition_raw_read(d, cert_offset, cert, cert_size);
|
||||||
|
|
||||||
_decrypt_title_key(tik, d->disc_key);
|
decrypt_title_key(tik, d->disc_key);
|
||||||
|
|
||||||
partition_raw_read(d, h3_offset, 0, 0x18000);
|
partition_raw_read(d, h3_offset, 0, 0x18000);
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@ extern "C"
|
|||||||
// effectively remove not copied partition from the partition table.
|
// effectively remove not copied partition from the partition table.
|
||||||
void wd_fix_partition_table(partition_selector_t selector, u8 *partition_table);
|
void wd_fix_partition_table(partition_selector_t selector, u8 *partition_table);
|
||||||
|
|
||||||
|
// needed for wad decryption
|
||||||
|
void decrypt_title_key(u8 *tik, u8 *title_key);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
@ -1150,6 +1150,7 @@ void CMenu::_buildMenus(void)
|
|||||||
_initCoverBanner();
|
_initCoverBanner();
|
||||||
_initExplorer();
|
_initExplorer();
|
||||||
_initBoot();
|
_initBoot();
|
||||||
|
_initWad();
|
||||||
|
|
||||||
_loadCFCfg();
|
_loadCFCfg();
|
||||||
}
|
}
|
||||||
|
@ -847,6 +847,7 @@ private:
|
|||||||
void _initHomeAndExitToMenu();
|
void _initHomeAndExitToMenu();
|
||||||
void _initCoverBanner();
|
void _initCoverBanner();
|
||||||
void _initExplorer();
|
void _initExplorer();
|
||||||
|
void _initWad();
|
||||||
//
|
//
|
||||||
void _textSource(void);
|
void _textSource(void);
|
||||||
void _textPluginSettings(void);
|
void _textPluginSettings(void);
|
||||||
@ -875,6 +876,7 @@ private:
|
|||||||
void _textBoot(void);
|
void _textBoot(void);
|
||||||
void _textCoverBanner(void);
|
void _textCoverBanner(void);
|
||||||
void _textExplorer(void);
|
void _textExplorer(void);
|
||||||
|
void _textWad(void);
|
||||||
//
|
//
|
||||||
void _refreshBoot();
|
void _refreshBoot();
|
||||||
void _refreshExplorer(s8 direction = 0);
|
void _refreshExplorer(s8 direction = 0);
|
||||||
@ -908,6 +910,7 @@ private:
|
|||||||
void _hideExitTo(bool instant = false);
|
void _hideExitTo(bool instant = false);
|
||||||
void _hideCoverBanner(bool instant = false);
|
void _hideCoverBanner(bool instant = false);
|
||||||
void _hideExplorer(bool instant = false);
|
void _hideExplorer(bool instant = false);
|
||||||
|
void _hideWad(bool instant = false);
|
||||||
//
|
//
|
||||||
void _showError(void);
|
void _showError(void);
|
||||||
void _showMain(void);
|
void _showMain(void);
|
||||||
@ -939,6 +942,7 @@ private:
|
|||||||
void _showExitTo(void);
|
void _showExitTo(void);
|
||||||
void _showCoverBanner(void);
|
void _showCoverBanner(void);
|
||||||
void _showExplorer(void);
|
void _showExplorer(void);
|
||||||
|
void _showWad(void);
|
||||||
void _updateSourceBtns(void);
|
void _updateSourceBtns(void);
|
||||||
void _updatePluginText(void);
|
void _updatePluginText(void);
|
||||||
void _updatePluginCheckboxes(void);
|
void _updatePluginCheckboxes(void);
|
||||||
@ -984,6 +988,7 @@ private:
|
|||||||
void _gameSettings(void);
|
void _gameSettings(void);
|
||||||
void _CoverBanner(void);
|
void _CoverBanner(void);
|
||||||
void _Explorer(void);
|
void _Explorer(void);
|
||||||
|
void _Wad(const char *wad_path = NULL);
|
||||||
void _CheatSettings();
|
void _CheatSettings();
|
||||||
bool _Source();
|
bool _Source();
|
||||||
void _PluginSettings();
|
void _PluginSettings();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "menu.hpp"
|
#include "menu.hpp"
|
||||||
|
#include "channel/nand.hpp"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
extern const u8 blank_png[];
|
extern const u8 blank_png[];
|
||||||
@ -24,6 +25,7 @@ extern const u8 blank_png[];
|
|||||||
TexData m_explorerBg;
|
TexData m_explorerBg;
|
||||||
s16 entries[8];
|
s16 entries[8];
|
||||||
s16 entries_sel[8];
|
s16 entries_sel[8];
|
||||||
|
char file[MAX_FAT_PATH];
|
||||||
char dir[MAX_FAT_PATH];
|
char dir[MAX_FAT_PATH];
|
||||||
char entries_char[7][NAME_MAX+1];
|
char entries_char[7][NAME_MAX+1];
|
||||||
u8 explorer_partition = 0;
|
u8 explorer_partition = 0;
|
||||||
@ -116,11 +118,13 @@ void CMenu::_Explorer(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char *file = fmt("%s%s", dir, entries_char[i-1]);
|
memset(file, 0, MAX_FAT_PATH);
|
||||||
|
strncpy(file, fmt("%s%s", dir, entries_char[i-1]), MAX_FAT_PATH);
|
||||||
if(strcasestr(file, ".mp3") != NULL || strcasestr(file, ".ogg") != NULL)
|
if(strcasestr(file, ".mp3") != NULL || strcasestr(file, ".ogg") != NULL)
|
||||||
MusicPlayer.LoadFile(file, false);
|
MusicPlayer.LoadFile(file, false);
|
||||||
else if(strcasestr(file, ".iso") != NULL || strcasestr(file, ".wbfs") != NULL)
|
else if(strcasestr(file, ".iso") != NULL || strcasestr(file, ".wbfs") != NULL)
|
||||||
{
|
{
|
||||||
|
_hideExplorer();
|
||||||
/* create header for id and path */
|
/* create header for id and path */
|
||||||
dir_discHdr tmpHdr;
|
dir_discHdr tmpHdr;
|
||||||
memset(&tmpHdr, 0, sizeof(dir_discHdr));
|
memset(&tmpHdr, 0, sizeof(dir_discHdr));
|
||||||
@ -141,6 +145,13 @@ void CMenu::_Explorer(void)
|
|||||||
currentPartition = explorer_partition;
|
currentPartition = explorer_partition;
|
||||||
_launchGC(&tmpHdr, false);
|
_launchGC(&tmpHdr, false);
|
||||||
}
|
}
|
||||||
|
_showExplorer();
|
||||||
|
}
|
||||||
|
else if(strcasestr(file, ".wad") != NULL)
|
||||||
|
{
|
||||||
|
_hideExplorer();
|
||||||
|
_Wad(file);
|
||||||
|
_showExplorer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
329
source/menu/menu_wad.cpp
Normal file
329
source/menu/menu_wad.cpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2013 FIX94
|
||||||
|
*
|
||||||
|
* 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, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "menu/menu.hpp"
|
||||||
|
#include "libwbfs/wiidisc.h"
|
||||||
|
#include "channel/nand.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "loader/sha1.h"
|
||||||
|
extern void aes_set_key(u8 *key);
|
||||||
|
extern void aes_decrypt_partial(u8 *inbuf, u8 *outbuf, u8 block[16],
|
||||||
|
u8 *ctext_ptr, u32 tmp_blockno);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WAD_BUF 0x10000
|
||||||
|
|
||||||
|
struct _hdr {
|
||||||
|
u32 header_len;
|
||||||
|
u16 type;
|
||||||
|
u16 padding;
|
||||||
|
u32 certs_len;
|
||||||
|
u32 crl_len;
|
||||||
|
u32 tik_len;
|
||||||
|
u32 tmd_len;
|
||||||
|
u32 data_len;
|
||||||
|
u32 footer_len;
|
||||||
|
} ATTRIBUTE_PACKED hdr;
|
||||||
|
|
||||||
|
void skip_align(FILE *f, u32 size)
|
||||||
|
{
|
||||||
|
size_t align_missing = (ALIGN(64, size) - size);
|
||||||
|
if(align_missing == 0)
|
||||||
|
return;
|
||||||
|
fseek(f, align_missing, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int installWad(const char *path)
|
||||||
|
{
|
||||||
|
gprintf("Installing %s\n", path);
|
||||||
|
const char *EmuNAND = NandHandle.GetPath();
|
||||||
|
|
||||||
|
if(!fsop_FileExist(path))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
u32 size = 0;
|
||||||
|
fsop_GetFileSizeBytes(path, &size);
|
||||||
|
if(size < sizeof(hdr))
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
FILE *wad_file = fopen(path, "rb");
|
||||||
|
fread(&hdr, sizeof(hdr), 1, wad_file);
|
||||||
|
skip_align(wad_file, sizeof(hdr));
|
||||||
|
|
||||||
|
if(size < (hdr.certs_len + hdr.crl_len + hdr.tik_len + hdr.tmd_len + hdr.data_len + hdr.footer_len)
|
||||||
|
|| hdr.tik_len == 0 || hdr.tmd_len == 0 || hdr.data_len == 0)
|
||||||
|
{
|
||||||
|
fclose(wad_file);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
fseek(wad_file, ALIGN(64, hdr.certs_len), SEEK_CUR);
|
||||||
|
fseek(wad_file, ALIGN(64, hdr.crl_len), SEEK_CUR);
|
||||||
|
|
||||||
|
gprintf("Reading tik\n");
|
||||||
|
u8 *tik_buf = (u8*)MEM2_alloc(hdr.tik_len);
|
||||||
|
fread(tik_buf, hdr.tik_len, 1, wad_file);
|
||||||
|
skip_align(wad_file, hdr.tik_len);
|
||||||
|
|
||||||
|
gprintf("Decrypting key\n");
|
||||||
|
u8 tik_key[16];
|
||||||
|
decrypt_title_key(tik_buf, tik_key);
|
||||||
|
aes_set_key(tik_key);
|
||||||
|
|
||||||
|
gprintf("Reading tmd\n");
|
||||||
|
signed_blob *tmd_buf = (signed_blob*)MEM2_alloc(hdr.tmd_len);
|
||||||
|
fread(tmd_buf, hdr.tmd_len, 1, wad_file);
|
||||||
|
skip_align(wad_file, hdr.tmd_len);
|
||||||
|
|
||||||
|
const tmd *tmd_ptr = (const tmd*)SIGNATURE_PAYLOAD(tmd_buf);
|
||||||
|
u64 tid = tmd_ptr->title_id;
|
||||||
|
|
||||||
|
/* ONLY allow wii channels for now */
|
||||||
|
if((u32)(tid>>32) != 0x00010001)
|
||||||
|
{
|
||||||
|
gprintf("No Wii Channel!\n");
|
||||||
|
free(tmd_buf);
|
||||||
|
free(tik_buf);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
u32 uid_size = 0;
|
||||||
|
u8 *uid_buf = fsop_ReadFile(fmt("%s/sys/uid.sys", EmuNAND), &uid_size);
|
||||||
|
if(uid_buf == NULL)
|
||||||
|
{
|
||||||
|
gprintf("No uid.sys found!\n");
|
||||||
|
free(tmd_buf);
|
||||||
|
free(tik_buf);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
else if(uid_size % 0xC != 0)
|
||||||
|
{
|
||||||
|
gprintf("uid.sys size is invalid!\n");
|
||||||
|
free(tmd_buf);
|
||||||
|
free(tik_buf);
|
||||||
|
free(uid_buf);
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool chan_exist = false;
|
||||||
|
uid *uid_file = (uid*)uid_buf;
|
||||||
|
u32 chans = uid_size/sizeof(uid);
|
||||||
|
for(u32 i = 0; i < chans; ++i)
|
||||||
|
{
|
||||||
|
if(uid_file[i].TitleID == tid)
|
||||||
|
chan_exist = true;
|
||||||
|
}
|
||||||
|
if(chan_exist == false)
|
||||||
|
{
|
||||||
|
gprintf("Updating uid.sys\n");
|
||||||
|
u32 new_uid_size = (chans+1)*sizeof(uid);
|
||||||
|
u8 *new_uid_buf = (u8*)MEM2_alloc(new_uid_size);
|
||||||
|
memset(new_uid_buf, 0, new_uid_size);
|
||||||
|
/* copy over old uid */
|
||||||
|
memcpy(new_uid_buf, uid_buf, chans*sizeof(uid));
|
||||||
|
uid *new_uid_file = (uid*)new_uid_buf;
|
||||||
|
new_uid_file[chans].TitleID = tid;
|
||||||
|
new_uid_file[chans].uid = 0x1000+chans;
|
||||||
|
fsop_WriteFile(fmt("%s/sys/uid.sys", EmuNAND), new_uid_file, new_uid_size);
|
||||||
|
}
|
||||||
|
/* clear old tik */
|
||||||
|
fsop_deleteFile(fmt("%s/ticket/%08x/%08x.tik", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF));
|
||||||
|
/* clear old content */
|
||||||
|
fsop_deleteFolder(fmt("%s/title/%08x/%08x/content", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF));
|
||||||
|
|
||||||
|
/* (re)create folder structure */
|
||||||
|
fsop_MakeFolder(fmt("%s/ticket", EmuNAND));
|
||||||
|
fsop_MakeFolder(fmt("%s/ticket/%08x", EmuNAND, (u32)(tid>>32)));
|
||||||
|
|
||||||
|
fsop_MakeFolder(fmt("%s/title", EmuNAND));
|
||||||
|
fsop_MakeFolder(fmt("%s/title/%08x", EmuNAND, (u32)(tid>>32)));
|
||||||
|
fsop_MakeFolder(fmt("%s/title/%08x/%08x", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF));
|
||||||
|
fsop_MakeFolder(fmt("%s/title/%08x/%08x/content", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF));
|
||||||
|
fsop_MakeFolder(fmt("%s/title/%08x/%08x/data", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF));
|
||||||
|
|
||||||
|
int hash_errors = 0;
|
||||||
|
|
||||||
|
/* decrypt and write app files */
|
||||||
|
for(u16 cnt = 0; cnt < tmd_ptr->num_contents; cnt++)
|
||||||
|
{
|
||||||
|
u8 iv[16];
|
||||||
|
const tmd_content *content = &tmd_ptr->contents[cnt];
|
||||||
|
u16 content_index = content->index;
|
||||||
|
memset(iv, 0, 16);
|
||||||
|
memcpy(iv, &content_index, 2);
|
||||||
|
/* longass filename */
|
||||||
|
const char *app_name = fmt("%s/title/%08x/%08x/content/%08x.app", EmuNAND,
|
||||||
|
(u32)(tid>>32), (u32)tid&0xFFFFFFFF, content->cid);
|
||||||
|
FILE *app_file = fopen(app_name, "wb");
|
||||||
|
|
||||||
|
u64 read = 0;
|
||||||
|
u8 *encBuf = (u8*)MEM2_alloc(WAD_BUF);
|
||||||
|
u8 *decBuf = (u8*)MEM2_alloc(WAD_BUF);
|
||||||
|
|
||||||
|
u8 block[16];
|
||||||
|
u8 prev_block[16];
|
||||||
|
u8 *ctext_ptr = iv;
|
||||||
|
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
SHA1Init(&ctx);
|
||||||
|
|
||||||
|
u32 size_enc_full = ALIGN(16, content->size);
|
||||||
|
while(read < size_enc_full)
|
||||||
|
{
|
||||||
|
u64 size_enc = (size_enc_full - read);
|
||||||
|
if (size_enc > WAD_BUF)
|
||||||
|
size_enc = WAD_BUF;
|
||||||
|
|
||||||
|
memset(encBuf, 0, WAD_BUF);
|
||||||
|
fread(encBuf, size_enc, 1, wad_file);
|
||||||
|
|
||||||
|
u32 partnr = 0;
|
||||||
|
u32 lastnr = (size_enc / sizeof(block));
|
||||||
|
|
||||||
|
for(partnr = 0; partnr < lastnr; partnr++)
|
||||||
|
{
|
||||||
|
aes_decrypt_partial(encBuf, decBuf, block, ctext_ptr, partnr);
|
||||||
|
memcpy(prev_block, encBuf + (partnr * 16), 16);
|
||||||
|
ctext_ptr = prev_block;
|
||||||
|
}
|
||||||
|
/* we need to work with the real size here */
|
||||||
|
u64 size_dec = (content->size - read);
|
||||||
|
if(size_dec > WAD_BUF)
|
||||||
|
size_dec = WAD_BUF;
|
||||||
|
SHA1Update(&ctx, decBuf, size_dec);
|
||||||
|
fwrite(decBuf, size_dec, 1, app_file);
|
||||||
|
/* dont forget to increase the read size */
|
||||||
|
read += size_enc;
|
||||||
|
}
|
||||||
|
sha1 app_sha1;
|
||||||
|
SHA1Final(app_sha1, &ctx);
|
||||||
|
skip_align(wad_file, size_enc_full);
|
||||||
|
gprintf("Wrote %s\n", app_name);
|
||||||
|
fclose(app_file);
|
||||||
|
|
||||||
|
if(memcmp(app_sha1, content->hash, sizeof(sha1)) == 0)
|
||||||
|
gprintf("sha1 matches on %08x.app, success!\n", content->cid);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gprintf("sha1 mismatch on %08x.app!\n", content->cid);
|
||||||
|
hash_errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsop_WriteFile(fmt("%s/ticket/%08x/%08x.tik", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF), tik_buf, hdr.tik_len);
|
||||||
|
fsop_WriteFile(fmt("%s/title/%08x/%08x/content/title.tmd", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF), tmd_buf, hdr.tmd_len);
|
||||||
|
|
||||||
|
free(tik_buf);
|
||||||
|
free(tmd_buf);
|
||||||
|
|
||||||
|
return hash_errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 m_wadBtnInstall;
|
||||||
|
s16 m_wadLblTitle;
|
||||||
|
s16 m_wadLblDialog;
|
||||||
|
|
||||||
|
void CMenu::_showWad()
|
||||||
|
{
|
||||||
|
m_btnMgr.show(m_wadBtnInstall);
|
||||||
|
m_btnMgr.show(m_wadLblTitle);
|
||||||
|
m_btnMgr.show(m_wadLblDialog);
|
||||||
|
/* partition selection */
|
||||||
|
m_btnMgr.show(m_configLblPartitionName);
|
||||||
|
m_btnMgr.show(m_configLblPartition);
|
||||||
|
m_btnMgr.show(m_configBtnPartitionP);
|
||||||
|
m_btnMgr.show(m_configBtnPartitionM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMenu::_hideWad(bool instant)
|
||||||
|
{
|
||||||
|
m_btnMgr.hide(m_wadBtnInstall, instant);
|
||||||
|
m_btnMgr.hide(m_wadLblTitle, instant);
|
||||||
|
m_btnMgr.hide(m_wadLblDialog, instant);
|
||||||
|
/* partition selection */
|
||||||
|
m_btnMgr.hide(m_configLblPartitionName);
|
||||||
|
m_btnMgr.hide(m_configLblPartition);
|
||||||
|
m_btnMgr.hide(m_configBtnPartitionP);
|
||||||
|
m_btnMgr.hide(m_configBtnPartitionM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMenu::_Wad(const char *wad_path)
|
||||||
|
{
|
||||||
|
if(wad_path == NULL)
|
||||||
|
return;
|
||||||
|
u8 part = currentPartition;
|
||||||
|
m_btnMgr.setText(m_wadLblDialog, wfmt(_fmt("wad3", L"Selected %s, after the installation you return to the explorer."), (strrchr(wad_path, '/')+1)));
|
||||||
|
m_btnMgr.setText(m_configLblPartition, upperCase(DeviceName[currentPartition]));
|
||||||
|
_showWad();
|
||||||
|
|
||||||
|
while(!m_exit)
|
||||||
|
{
|
||||||
|
_mainLoopCommon();
|
||||||
|
if(BTN_HOME_PRESSED || BTN_B_PRESSED)
|
||||||
|
break;
|
||||||
|
else if(BTN_A_PRESSED)
|
||||||
|
{
|
||||||
|
if(m_btnMgr.selected(m_wadBtnInstall))
|
||||||
|
{
|
||||||
|
_hideWad(true);
|
||||||
|
m_btnMgr.setText(m_wbfsLblMessage, _t("wad4", L"Installing WAD, please wait..."));
|
||||||
|
m_btnMgr.show(m_wbfsLblMessage, true);
|
||||||
|
/* who cares about making a thread, just refresh a second */
|
||||||
|
for(u8 i = 0; i < 60; ++i)
|
||||||
|
_mainLoopCommon();
|
||||||
|
/* setup emu nand paths */
|
||||||
|
const char *emu_char = m_cfg.getString(CHANNEL_DOMAIN, "path", "/").c_str();
|
||||||
|
NandHandle.SetPaths(emu_char, DeviceName[currentPartition]);
|
||||||
|
int result = installWad(wad_path);
|
||||||
|
if(result < 0)
|
||||||
|
m_btnMgr.setText(m_wbfsLblMessage, wfmt(_fmt("wad5", L"Installation error %i!"), result));
|
||||||
|
else
|
||||||
|
m_btnMgr.setText(m_wbfsLblMessage, wfmt(_fmt("wad6", L"Installation finished with %i hash fails."), result));
|
||||||
|
}
|
||||||
|
else if((m_btnMgr.selected(m_configBtnPartitionP) || m_btnMgr.selected(m_configBtnPartitionM)))
|
||||||
|
{
|
||||||
|
s8 direction = m_btnMgr.selected(m_configBtnPartitionP) ? 1 : -1;
|
||||||
|
_setPartition(direction);
|
||||||
|
m_btnMgr.setText(m_configLblPartition, upperCase(DeviceName[currentPartition]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
currentPartition = part;
|
||||||
|
_hideWad();
|
||||||
|
/* onscreen message might be onscreen still */
|
||||||
|
m_btnMgr.hide(m_wbfsLblMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMenu::_initWad()
|
||||||
|
{
|
||||||
|
m_wadLblTitle = _addTitle("WAD/TITLE", theme.titleFont, L"", 20, 30, 600, 60, theme.titleFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE);
|
||||||
|
m_wadLblDialog = _addLabel("WAD/DIALOG", theme.lblFont, L"", 40, 90, 560, 200, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE);
|
||||||
|
m_wadBtnInstall = _addButton("WAD/INSTALL_BTN", theme.btnFont, L"", 420, 400, 200, 56, theme.btnFontColor);
|
||||||
|
|
||||||
|
_setHideAnim(m_wadLblTitle, "WAD/TITLE", 0, 0, -2.f, 0.f);
|
||||||
|
_setHideAnim(m_wadLblDialog, "WAD/DIALOG", 0, 0, -2.f, 0.f);
|
||||||
|
_setHideAnim(m_wadBtnInstall, "WAD/INSTALL_BTN", 0, 0, -2.f, 0.f);
|
||||||
|
|
||||||
|
_hideWad(true);
|
||||||
|
_textWad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMenu::_textWad()
|
||||||
|
{
|
||||||
|
m_btnMgr.setText(m_wadLblTitle, _t("wad1", L"Install WAD"));
|
||||||
|
m_btnMgr.setText(m_wadBtnInstall, _t("wad2", L"Go"));
|
||||||
|
}
|
@ -321,6 +321,12 @@ vmpall=All
|
|||||||
vmpmore=More
|
vmpmore=More
|
||||||
vmpnone=None
|
vmpnone=None
|
||||||
vmpnormal=Normal
|
vmpnormal=Normal
|
||||||
|
wad1=Install WAD
|
||||||
|
wad2=Go
|
||||||
|
wad3=Selected %s, after the installation you return to the explorer.
|
||||||
|
wad4=Installing WAD, please wait...
|
||||||
|
wad5=Installation error %i!
|
||||||
|
wad6=Installation finished with %i hash fails.
|
||||||
wbfsadddlg=Please insert the disc you want to copy, then click on Go.
|
wbfsadddlg=Please insert the disc you want to copy, then click on Go.
|
||||||
wbfscpydlg=If you are sure you want to copy this game to SD, click on Go.
|
wbfscpydlg=If you are sure you want to copy this game to SD, click on Go.
|
||||||
wbfsop1=Install Game
|
wbfsop1=Install Game
|
||||||
|
Loading…
Reference in New Issue
Block a user