usbloadergx/source/wad/nandtitle.cpp

436 lines
8.6 KiB
C++
Raw Normal View History

#include "nandtitle.h"
#include "usbloader/playlog.h"
#include "gecko.h"
2010-09-24 15:46:32 +02:00
NandTitle NandTitles;
2010-09-24 02:48:03 +02:00
static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN( 32 );
//based on one from comex's nand formatter
2010-09-24 02:48:03 +02:00
static u64 atoi_hex(const char *s)
{
u64 ret = 0;
u32 n = strlen(s);
for (u32 i = 0; i < n; i++)
{
if (s[i] > 0x39)
{
ret += (s[i] & ~0x20) - 0x37;
}
else
{
ret += (s[i] - 0x30);
}
if (i != (n - 1)) ret *= 16;
}
return ret;
}
NandTitle::NandTitle()
{
currentIndex = 0;
currentType = 0;
}
NandTitle::~NandTitle()
{
2010-09-19 15:03:16 +02:00
titleIds.clear();
NameList.clear();
}
s32 NandTitle::Get()
{
s32 ret;
2010-09-19 15:03:16 +02:00
u64 *list = NULL;
u32 numTitles = 0;
2010-09-19 15:03:16 +02:00
titleIds.clear();
NameList.clear();
2010-09-24 02:48:03 +02:00
ret = ES_GetNumTitles(&numTitles);
if (ret < 0) return WII_EINTERNAL;
2010-09-24 02:48:03 +02:00
list = (u64*) memalign(32, numTitles * sizeof(u64));
if (!list)
{
return -1;
}
2010-09-24 02:48:03 +02:00
ret = ES_GetTitles(list, numTitles);
if (ret < 0)
{
2010-09-24 02:48:03 +02:00
free(list);
return WII_EINTERNAL;
}
2010-09-24 02:48:03 +02:00
for (u32 i = 0; i < numTitles; i++)
{
2010-09-24 02:48:03 +02:00
titleIds.push_back(list[i]);
}
2010-09-19 15:03:16 +02:00
2010-09-24 02:48:03 +02:00
free(list);
2010-09-19 15:03:16 +02:00
int language = CONF_GetLanguage();
ISFS_Initialize();
2010-09-24 02:48:03 +02:00
wchar_t name[IMET_MAX_NAME_LEN];
2010-09-24 02:48:03 +02:00
for (u32 i = 0; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
bool r = GetName(titleIds.at(i), language, name);
if (r)
{
2010-09-24 02:48:03 +02:00
wString wsname(name);
NameList[titleIds.at(i)] = wsname.toUTF8();
}
}
ISFS_Deinitialize();
//If not started from SystemMenu, create playlog while we got nand access.
Playlog_Create();
return 1;
}
2010-09-24 02:48:03 +02:00
tmd* NandTitle::GetTMD(u64 tid)
{
//gprintf("GetTMD( %016llx ): ", tid );
2010-09-24 02:48:03 +02:00
signed_blob *s_tmd = (signed_blob *) tmd_buf;
u32 tmd_size;
2010-09-24 02:48:03 +02:00
if (ES_GetStoredTMDSize(tid, &tmd_size) < 0)
{
//gprintf("!size\n");
return NULL;
}
2010-09-24 02:48:03 +02:00
s32 ret = ES_GetStoredTMD(tid, s_tmd, tmd_size);
if (ret < 0)
{
//gprintf("!tmd - %04x\n", ret );
return NULL;
}
2010-09-24 02:48:03 +02:00
tmd *t = (tmd*) SIGNATURE_PAYLOAD(s_tmd);
//gprintf("ok\n");
return t;
}
2010-09-24 02:48:03 +02:00
bool NandTitle::GetName(u64 tid, int language, wchar_t* name)
{
2010-09-24 02:48:03 +02:00
if (TITLE_UPPER( tid ) != 0x10001 && TITLE_UPPER( tid ) != 0x10002 && TITLE_UPPER( tid ) != 0x10004) return false;
//gprintf("GetName( %016llx ): ", tid );
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
2010-09-24 02:48:03 +02:00
IMET *imet = (IMET*) memalign(32, sizeof(IMET));
2010-09-24 02:48:03 +02:00
tmd* titleTmd = GetTMD(tid);
if (!titleTmd)
{
//gprintf("no TMD\n");
2010-09-24 02:48:03 +02:00
free(imet);
return false;
}
u16 i;
bool ok = false;
2010-09-24 02:48:03 +02:00
for (i = 0; i < titleTmd->num_contents; i++)
{
2010-09-24 02:48:03 +02:00
if (!titleTmd->contents[i].index)
{
ok = true;
break;
}
}
2010-09-24 02:48:03 +02:00
if (!ok)
{
2010-09-24 02:48:03 +02:00
free(imet);
return false;
}
2010-09-24 02:48:03 +02:00
snprintf(app, sizeof(app), "/title/%08x/%08x/content/%08x.app", TITLE_UPPER( tid ), TITLE_LOWER( tid ),
titleTmd->contents[i].cid);
//gprintf("%s\n", app );
2010-09-24 02:48:03 +02:00
if (language > CONF_LANG_KOREAN) language = CONF_LANG_ENGLISH;
2010-09-24 02:48:03 +02:00
s32 fd = ISFS_Open(app, ISFS_OPEN_READ);
if (fd < 0)
{
//gprintf("fd: %d\n", fd );
2010-09-24 02:48:03 +02:00
free(imet);
return false;
}
2010-09-24 02:48:03 +02:00
if (ISFS_Seek(fd, IMET_OFFSET, SEEK_SET) != IMET_OFFSET)
{
2010-09-24 02:48:03 +02:00
ISFS_Close(fd);
free(imet);
return false;
}
2010-09-24 02:48:03 +02:00
if (ISFS_Read(fd, imet, sizeof(IMET)) != sizeof(IMET))
{
2010-09-24 02:48:03 +02:00
ISFS_Close(fd);
free(imet);
return false;
}
2010-09-24 02:48:03 +02:00
ISFS_Close(fd);
2010-09-24 02:48:03 +02:00
if (imet->sig != IMET_SIGNATURE)
{
2010-09-24 02:48:03 +02:00
free(imet);
return false;
}
2010-09-24 02:48:03 +02:00
if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0)
{
// channel name is not available in system language
2010-09-24 02:48:03 +02:00
if (imet->name_english[0] != 0)
{
language = CONF_LANG_ENGLISH;
}
else
{
// channel name is also not available on english, get ascii name
2010-09-24 02:48:03 +02:00
for (int i = 0; i < 4; i++)
{
2010-09-24 02:48:03 +02:00
name[i] = (TITLE_LOWER( tid ) >> (24 - i * 8)) & 0xFF;
}
2010-09-24 02:48:03 +02:00
name[4] = 0;
free(imet);
return true;
}
}
// retrieve channel name in system language or on english
2010-09-24 02:48:03 +02:00
for (int i = 0; i < IMET_MAX_NAME_LEN; i++)
{
2010-09-24 02:48:03 +02:00
name[i] = imet->name_japanese[i + (language * IMET_MAX_NAME_LEN)];
}
2010-09-24 02:48:03 +02:00
free(imet);
return true;
}
2010-09-24 02:48:03 +02:00
bool NandTitle::Exists(u64 tid)
{
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
2010-09-24 02:48:03 +02:00
tmd* titleTmd = GetTMD(tid);
if (!titleTmd) return false;
u16 i;
bool ok = false;
2010-09-24 02:48:03 +02:00
for (i = 0; i < titleTmd->num_contents; i++)
{
2010-09-24 02:48:03 +02:00
if (!titleTmd->contents[i].index)
{
ok = true;
break;
}
}
2010-09-24 02:48:03 +02:00
if (!ok) return false;
2010-09-24 02:48:03 +02:00
snprintf(app, sizeof(app), "/title/%08x/%08x/content/%08x.app", TITLE_UPPER( tid ), TITLE_LOWER( tid ),
titleTmd->contents[i].cid);
s32 fd = ISFS_Open(app, ISFS_OPEN_READ);
if (fd >= 0) ISFS_Close(fd);
//gprintf(" fd: %d\n", fd );
return fd >= 0 || fd == -102; //102 means it exists, but we dont have permission to open it
}
2010-09-24 02:48:03 +02:00
bool NandTitle::ExistsFromIndex(u32 i)
{
if (i > titleIds.size()) return false;
2010-09-24 02:48:03 +02:00
return Exists(titleIds.at(i));
}
2010-09-24 02:48:03 +02:00
u64 NandTitle::At(u32 i)
{
if (i > titleIds.size()) return 0;
2010-09-24 02:48:03 +02:00
return titleIds.at(i);
}
2010-09-24 02:48:03 +02:00
int NandTitle::IndexOf(u64 tid)
{
2010-09-24 02:48:03 +02:00
for (u32 i = 0; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
if (titleIds.at(i) == tid) return i;
}
return WII_EINSTALL;
}
2010-09-24 02:48:03 +02:00
const char* NandTitle::NameOf(u64 tid)
{
2010-09-24 02:48:03 +02:00
map<u64, string>::iterator itr = NameList.find(tid);
if (itr != NameList.end()) return itr->second.c_str();
return NULL;
}
2010-09-24 02:48:03 +02:00
const char* NandTitle::NameFromIndex(u32 i)
{
if (i > titleIds.size()) return NULL;
2010-09-24 02:48:03 +02:00
map<u64, string>::iterator itr = NameList.find(titleIds.at(i));
if (itr != NameList.end()) return itr->second.c_str();
2010-09-19 15:03:16 +02:00
return NULL;
}
2010-09-24 02:48:03 +02:00
u16 NandTitle::VersionOf(u64 tid)
{
2010-09-24 02:48:03 +02:00
for (u32 i = 0; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
if (titleIds.at(i) == tid)
{
2010-09-24 02:48:03 +02:00
tmd* Tmd = GetTMD(tid);
if (!Tmd) break;
return Tmd->title_version;
}
}
return 0;
}
2010-09-24 02:48:03 +02:00
u16 NandTitle::VersionFromIndex(u32 i)
{
if (i > titleIds.size()) return 0;
2010-09-24 02:48:03 +02:00
tmd* Tmd = GetTMD(titleIds.at(i));
if (!Tmd) return 0;
return Tmd->title_version;
}
2010-09-24 02:48:03 +02:00
u32 NandTitle::CountType(u32 type)
{
u32 ret = 0;
2010-09-24 02:48:03 +02:00
for (u32 i = 0; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
if (TITLE_UPPER( titleIds.at( i ) ) == type)
{
ret++;
}
}
return ret;
}
2010-09-24 02:48:03 +02:00
u32 NandTitle::SetType(u32 upper)
{
currentType = upper;
currentIndex = 0;
2010-09-24 02:48:03 +02:00
return CountType(upper);
}
u64 NandTitle::Next()
{
u64 ret = 0;
//gprintf("Next( %08x, %u )\n", currentType, currentIndex );
u32 i;
2010-09-24 02:48:03 +02:00
for (i = currentIndex; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
if (currentType)
{
2010-09-24 02:48:03 +02:00
if (currentType == TITLE_UPPER( titleIds.at( i ) ))
{
2010-09-24 02:48:03 +02:00
ret = titleIds.at(i);
break;
}
}
else
{
2010-09-24 02:48:03 +02:00
ret = titleIds.at(i);
break;
}
}
currentIndex = i + 1;
return ret;
}
void NandTitle::ResetCounter()
{
currentIndex = 0;
}
2010-09-24 02:48:03 +02:00
void NandTitle::AsciiTID(u64 tid, char* out)
{
//gprintf("AsciiTID( %016llx ): ");
2010-09-24 02:48:03 +02:00
out[0] = ascii(TITLE_3( tid ));
out[1] = ascii(TITLE_2( tid ));
out[2] = ascii(TITLE_1( tid ));
out[3] = ascii((u8) (tid));
out[4] = 0;
//gprintf("%s\n", out );
}
2010-09-24 02:48:03 +02:00
void NandTitle::AsciiFromIndex(u32 i, char* out)
{
if (i > titleIds.size())
{
2010-09-24 02:48:03 +02:00
out[0] = 0;
return;
}
2010-09-24 02:48:03 +02:00
AsciiTID(titleIds.at(i), out);
}
2010-09-24 02:48:03 +02:00
s32 NandTitle::GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen)
{
tikview *views = NULL;
u32 nb_views;
s32 ret;
/* Get number of ticket views */
2010-09-24 02:48:03 +02:00
ret = ES_GetNumTicketViews(tid, &nb_views);
if (ret < 0) return ret;
/* Allocate memory */
2010-09-24 02:48:03 +02:00
views = (tikview *) memalign(32, sizeof(tikview) * nb_views);
if (!views) return -1;
/* Get ticket views */
2010-09-24 02:48:03 +02:00
ret = ES_GetTicketViews(tid, views, nb_views);
if (ret < 0) goto err;
/* Set values */
*outbuf = views;
*outlen = nb_views;
return 0;
2010-09-24 02:48:03 +02:00
err:
/* Free memory */
2010-09-24 02:48:03 +02:00
if (views) free(views);
return ret;
}
2010-09-24 02:48:03 +02:00
int NandTitle::FindU64(const char *s)
{
2010-09-24 02:48:03 +02:00
u64 tid = atoi_hex(s);
return IndexOf(tid);
}
2010-09-24 02:48:03 +02:00
int NandTitle::FindU32(const char *s)
{
2010-09-24 02:48:03 +02:00
u64 tid = atoi_hex(s);
for (u32 i = 0; i < titleIds.size(); i++)
{
2010-09-24 02:48:03 +02:00
if (TITLE_LOWER( titleIds.at( i ) ) == TITLE_LOWER( tid )) return i;
}
return WII_EINSTALL;
}