2012-01-21 21:57:41 +01:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2010
|
|
|
|
* by dude
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Channel Launcher Class
|
|
|
|
*
|
|
|
|
* for WiiXplorer 2010
|
|
|
|
***************************************************************************/
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "channel_launcher.h"
|
2012-01-21 21:57:41 +01:00
|
|
|
#include "channels.h"
|
|
|
|
#include "banner.h"
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "config/config.hpp"
|
|
|
|
#include "gecko/gecko.h"
|
|
|
|
#include "gui/text.hpp"
|
|
|
|
#include "loader/fs.h"
|
|
|
|
#include "memory/mem2.hpp"
|
|
|
|
#include "wstringEx/wstringEx.hpp"
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
#define DOWNLOADED_CHANNELS 0x00010001
|
|
|
|
#define SYSTEM_CHANNELS 0x00010002
|
|
|
|
#define RF_NEWS_CHANNEL 0x48414741
|
|
|
|
#define RF_FORECAST_CHANNEL 0x48414641
|
|
|
|
|
|
|
|
extern "C" void ShowError(const wstringEx &error);
|
|
|
|
#define error(x) //ShowError(x)
|
|
|
|
|
|
|
|
Channels::Channels()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Channels::Init(u32 channelType, string lang, bool reload)
|
|
|
|
{
|
|
|
|
if (reload) init = !reload;
|
|
|
|
if (!init || channelType != this->channelType ||
|
|
|
|
lang != this->langCode)
|
|
|
|
{
|
|
|
|
this->channelType = channelType;
|
|
|
|
this->langCode = lang;
|
|
|
|
|
|
|
|
this->channels.clear();
|
|
|
|
Search(channelType, lang);
|
|
|
|
init = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Channels::~Channels()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-07-10 13:25:27 +02:00
|
|
|
u32 Channels::Load(u64 title)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
|
|
|
|
u32 bootcontent;
|
2012-05-20 14:34:48 +02:00
|
|
|
u32 entry = 0;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
if(!GetAppNameFromTmd(title, app, true, &bootcontent))
|
2012-05-20 14:34:48 +02:00
|
|
|
return entry;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-05-24 00:09:11 +02:00
|
|
|
u8 *data = GetDol(title, bootcontent);
|
2012-05-20 14:34:48 +02:00
|
|
|
|
2012-07-10 13:25:27 +02:00
|
|
|
Identify(title);
|
2012-05-20 14:34:48 +02:00
|
|
|
entry = LoadChannel(data);
|
|
|
|
free(data);
|
|
|
|
|
|
|
|
return entry;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 Channels::GetRequestedIOS(u64 title)
|
|
|
|
{
|
|
|
|
u8 IOS = 0;
|
|
|
|
|
|
|
|
char tmd[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
|
|
|
|
sprintf(tmd, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title));
|
|
|
|
|
|
|
|
u32 size;
|
2012-05-13 19:25:26 +02:00
|
|
|
u8 *titleTMD = (u8 *)ISFS_GetFile((u8 *) &tmd, &size, -1);
|
|
|
|
if(titleTMD == NULL)
|
|
|
|
return 0;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
if(size > 0x18B)
|
|
|
|
IOS = titleTMD[0x18B];
|
2012-05-13 17:13:33 +02:00
|
|
|
|
2012-07-27 19:26:49 +02:00
|
|
|
free(titleTMD);
|
2012-07-10 13:25:27 +02:00
|
|
|
gprintf("Requested Game IOS: %i\n", IOS);
|
2012-01-21 21:57:41 +01:00
|
|
|
return IOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64* Channels::GetChannelList(u32* count)
|
|
|
|
{
|
|
|
|
u32 countall;
|
|
|
|
if (ES_GetNumTitles(&countall) < 0 || !countall) return NULL;
|
|
|
|
|
|
|
|
u64* titles = (u64*)MEM2_alloc(countall * sizeof(u64));
|
2012-05-13 19:25:26 +02:00
|
|
|
if (!titles)
|
|
|
|
return NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
if(ES_GetTitles(titles, countall) < 0)
|
|
|
|
{
|
2012-07-27 19:26:49 +02:00
|
|
|
free(titles);
|
2012-01-21 21:57:41 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64* channels = (u64*)MEM2_alloc(countall * sizeof(u64));
|
|
|
|
if (!channels)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*count = 0;
|
|
|
|
for (u32 i = 0; i < countall; i++)
|
|
|
|
{
|
|
|
|
u32 type = TITLE_UPPER(titles[i]);
|
|
|
|
|
|
|
|
if (type == DOWNLOADED_CHANNELS || type == SYSTEM_CHANNELS)
|
|
|
|
{
|
|
|
|
if (TITLE_LOWER(titles[i]) == RF_NEWS_CHANNEL || // skip region free news and forecast channel
|
|
|
|
TITLE_LOWER(titles[i]) == RF_FORECAST_CHANNEL)
|
|
|
|
continue;
|
|
|
|
channels[(*count)++] = titles[i];
|
|
|
|
}
|
|
|
|
}
|
2012-07-27 19:26:49 +02:00
|
|
|
free(titles);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-05-13 19:25:26 +02:00
|
|
|
return(u64*)MEM2_realloc(channels, *count * sizeof(u64));
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2012-05-24 00:09:11 +02:00
|
|
|
bool Channels::GetAppNameFromTmd(u64 title, char *app, bool dol, u32 *bootcontent)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
char tmd[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
|
2012-02-03 23:38:00 +01:00
|
|
|
sprintf(tmd, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title));
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
u32 size;
|
|
|
|
u8 *data = ISFS_GetFile((u8 *) &tmd, &size, -1);
|
2012-05-13 19:25:26 +02:00
|
|
|
if (data == NULL || size < 0x208)
|
|
|
|
return ret;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-05-13 19:25:26 +02:00
|
|
|
_tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)data);
|
2012-01-21 21:57:41 +01:00
|
|
|
u16 i;
|
|
|
|
for(i = 0; i < tmd_file->num_contents; ++i)
|
2012-05-13 19:25:26 +02:00
|
|
|
{
|
2012-01-21 21:57:41 +01:00
|
|
|
if(tmd_file->contents[i].index == (dol ? tmd_file->boot_index : 0))
|
|
|
|
{
|
|
|
|
*bootcontent = tmd_file->contents[i].cid;
|
2012-02-03 23:38:00 +01:00
|
|
|
sprintf(app, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(title), TITLE_LOWER(title), *bootcontent);
|
2012-01-21 21:57:41 +01:00
|
|
|
ret = true;
|
|
|
|
break;
|
|
|
|
}
|
2012-05-13 19:25:26 +02:00
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-07-27 19:26:49 +02:00
|
|
|
free(data);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Banner * Channels::GetBanner(u64 title, bool imetOnly)
|
|
|
|
{
|
|
|
|
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
|
|
|
|
u32 cid;
|
|
|
|
if (!GetAppNameFromTmd(title, app, false, &cid))
|
|
|
|
{
|
|
|
|
gprintf("No title found\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return Banner::GetBanner(title, app, true, imetOnly);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::GetChannelNameFromApp(u64 title, wchar_t* name, int language)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (language > CONF_LANG_KOREAN)
|
|
|
|
language = CONF_LANG_ENGLISH;
|
|
|
|
|
|
|
|
Banner *banner = GetBanner(title, true);
|
|
|
|
if (banner != NULL)
|
|
|
|
{
|
|
|
|
ret = banner->GetName(name, language);
|
|
|
|
delete banner;
|
|
|
|
banner = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Channels::GetLanguage(const char *lang)
|
|
|
|
{
|
|
|
|
if (strncmp(lang, "JP", 2) == 0) return CONF_LANG_JAPANESE;
|
|
|
|
else if (strncmp(lang, "EN", 2) == 0) return CONF_LANG_ENGLISH;
|
|
|
|
else if (strncmp(lang, "DE", 2) == 0) return CONF_LANG_GERMAN;
|
|
|
|
else if (strncmp(lang, "FR", 2) == 0) return CONF_LANG_FRENCH;
|
|
|
|
else if (strncmp(lang, "ES", 2) == 0) return CONF_LANG_SPANISH;
|
|
|
|
else if (strncmp(lang, "IT", 2) == 0) return CONF_LANG_ITALIAN;
|
|
|
|
else if (strncmp(lang, "NL", 2) == 0) return CONF_LANG_DUTCH;
|
|
|
|
else if (strncmp(lang, "ZHTW", 4) == 0) return CONF_LANG_TRAD_CHINESE;
|
|
|
|
else if (strncmp(lang, "ZH", 2) == 0) return CONF_LANG_SIMP_CHINESE;
|
|
|
|
else if (strncmp(lang, "KO", 2) == 0) return CONF_LANG_KOREAN;
|
|
|
|
|
|
|
|
return CONF_LANG_ENGLISH; // Default to EN
|
|
|
|
}
|
|
|
|
|
|
|
|
void Channels::Search(u32 channelType, string lang)
|
|
|
|
{
|
|
|
|
u32 count;
|
|
|
|
u64* list = GetChannelList(&count);
|
2012-05-13 19:25:26 +02:00
|
|
|
if (list == NULL)
|
|
|
|
return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
int language = lang.size() == 0 ? CONF_GetLanguage() : GetLanguage(lang.c_str());
|
|
|
|
|
|
|
|
for (u32 i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
if (channelType == 0 || channelType == TITLE_UPPER(list[i]))
|
|
|
|
{
|
|
|
|
Channel channel;
|
|
|
|
if (GetChannelNameFromApp(list[i], channel.name, language))
|
|
|
|
{
|
|
|
|
channel.title = list[i];
|
|
|
|
|
|
|
|
u32 title_h = (u32)channel.title;
|
|
|
|
sprintf(channel.id, "%c%c%c%c", title_h >> 24, title_h >> 16, title_h >> 8, title_h);
|
|
|
|
|
|
|
|
channels.push_back(channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-27 19:26:49 +02:00
|
|
|
free(list);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
wchar_t * Channels::GetName(int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > Count() - 1)
|
|
|
|
{
|
|
|
|
return (wchar_t *) "";
|
|
|
|
}
|
|
|
|
return channels.at(index).name;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Channels::Count()
|
|
|
|
{
|
|
|
|
return channels.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
char * Channels::GetId(int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > Count() - 1) return (char *) "";
|
|
|
|
return channels.at(index).id;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 Channels::GetTitle(int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > Count() - 1) return 0;
|
|
|
|
return channels.at(index).title;
|
|
|
|
}
|
|
|
|
|
|
|
|
Channel * Channels::GetChannel(int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index > Count() - 1) return NULL;
|
|
|
|
return &channels.at(index);
|
|
|
|
}
|