mirror of
https://github.com/nitraiolo/CfgUSBLoader.git
synced 2025-01-09 01:40:43 +01:00
1220 lines
27 KiB
C
1220 lines
27 KiB
C
|
|
// by oggzee
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <ogcsys.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#define __LINUX_ERRNO_EXTENSIONS__ // for EBADFD
|
|
#include <sys/errno.h>
|
|
|
|
#include "disc.h"
|
|
#include "gui.h"
|
|
#include "wpad.h"
|
|
#include "cfg.h"
|
|
#include "http.h"
|
|
#include "dns.h"
|
|
#include "video.h"
|
|
#include "net.h"
|
|
#include "xml.h" /* XML - Lustar */
|
|
#include "menu.h"
|
|
#include "gettext.h"
|
|
#include "fat.h"
|
|
#include "cache.h"
|
|
#include "unzip/unzip.h"
|
|
#include "unzip/miniunz.h"
|
|
#include "fileOps.h"
|
|
|
|
extern struct discHdr *gameList;
|
|
extern s32 gameCnt, gameSelected, gameStart;
|
|
extern bool imageNotFound;
|
|
|
|
static int net_top = -1;
|
|
static int dl_abort = 0;
|
|
|
|
/*Networking - Forsaekn*/
|
|
int Net_Init(char *ip){
|
|
|
|
s32 result;
|
|
|
|
int count = 0;
|
|
while ((result = net_init()) == -EAGAIN && count < 100) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
usleep(50 * 1000); //50ms
|
|
count++;
|
|
}
|
|
|
|
if (result >= 0)
|
|
{
|
|
char myIP[16];
|
|
|
|
net_top = result;
|
|
if (if_config(myIP, NULL, NULL, true) < 0)
|
|
{
|
|
printf("Error reading IP address.");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Initialize Network */
|
|
bool Init_Net()
|
|
{
|
|
static bool firstTimeDownload = true;
|
|
|
|
if(firstTimeDownload == true){
|
|
char myIP[16];
|
|
printf_x(gt("Initializing Network..."));
|
|
printf("\n");
|
|
if( !Net_Init(myIP) ){
|
|
printf_(gt("Error Initializing Network."));
|
|
printf("\n");
|
|
return false;
|
|
}
|
|
printf_(gt("Network connection established."));
|
|
printf("\n");
|
|
firstTimeDownload = false;
|
|
}
|
|
__console_flush(0);
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_NET
|
|
#define debug_printf(fmt, args...) \
|
|
fprintf(stderr, "%s:%d:" fmt, __FUNCTION__, __LINE__, ##args)
|
|
#else
|
|
#define debug_printf(fmt, args...)
|
|
#endif // DEBUG_NET
|
|
|
|
#define STACK_ALIGN(type, name, cnt, alignment) u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + (((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - ((sizeof(type)*(cnt))%(alignment))) : 0))]; \
|
|
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (((u32)(_al__##name))&((alignment)-1))))
|
|
|
|
#define IOCTL_NWC24_CLEANUP 0x07
|
|
|
|
#define NET_UNKNOWN_ERROR_OFFSET -10000
|
|
|
|
static char __kd_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/kd/request";
|
|
|
|
// 0 means we don't know what this error code means
|
|
// I sense a pattern here...
|
|
static u8 _net_error_code_map[] = {
|
|
0, // 0
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 5
|
|
EAGAIN,
|
|
EALREADY,
|
|
EBADFD,
|
|
0,
|
|
0, // 10
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 15
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 20
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 25
|
|
EINPROGRESS,
|
|
0,
|
|
0,
|
|
0,
|
|
EISCONN, // 30
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 35
|
|
0,
|
|
0,
|
|
0,
|
|
ENETDOWN, //?
|
|
0, // 40
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 45
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 50
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 55
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // 60
|
|
};
|
|
|
|
static s32 _net_convert_error(s32 ios_retval)
|
|
{
|
|
// return ios_retval;
|
|
if (ios_retval >= 0) return ios_retval;
|
|
if (ios_retval < -sizeof(_net_error_code_map)
|
|
|| !_net_error_code_map[-ios_retval])
|
|
return NET_UNKNOWN_ERROR_OFFSET + ios_retval;
|
|
return -_net_error_code_map[-ios_retval];
|
|
}
|
|
|
|
// by oggzee
|
|
static s32 NWC24iCleanupSocket(void)
|
|
{
|
|
s32 kd_fd, ret;
|
|
STACK_ALIGN(u8, kd_buf, 0x20, 32);
|
|
|
|
kd_fd = _net_convert_error(IOS_Open(__kd_fs, 0));
|
|
if (kd_fd < 0) {
|
|
debug_printf(gt("IOS_Open(%s) failed with code %d"), __kd_fs, kd_fd);
|
|
printf("\n");
|
|
return kd_fd;
|
|
}
|
|
|
|
ret = _net_convert_error(IOS_Ioctl(kd_fd, IOCTL_NWC24_CLEANUP, NULL, 0, kd_buf, 0x20));
|
|
if (ret < 0) debug_printf("IOS_Ioctl(7)=%d\n", ret);
|
|
IOS_Close(kd_fd);
|
|
return ret;
|
|
}
|
|
|
|
void Net_Close(int close_wc24)
|
|
{
|
|
if (net_top >= 0) {
|
|
if (close_wc24) {
|
|
NWC24iCleanupSocket();
|
|
IOS_Close(net_top);
|
|
}
|
|
net_top = -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Channel regions:
|
|
|
|
A 41 All regions. System channels like the Mii channel use it.
|
|
D 44 German-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past
|
|
E 45 USA and other NTSC regions except Japan
|
|
F 46 French-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
|
|
J 4A Japan
|
|
K 4B Korea
|
|
L 4C Japanese Import to Europe, Australia and other PAL regions
|
|
M 4D American Import to Europe, Australia and other PAL regions
|
|
N 4E Japanese Import to USA and other NTSC regions
|
|
P 50 Europe, Australia and other PAL regions
|
|
Q 51 Korea with Japanese language.
|
|
T 54 Korea with English language.
|
|
X 58 Not a real region code. Used by DVDX and Homebrew Channel.
|
|
|
|
Game regions:
|
|
|
|
H Netherlands (quite rare)
|
|
I Italy
|
|
S Spain
|
|
X PAL (not sure if it is for a specific country,
|
|
but it was confirmed to be used on disc that only had French)
|
|
Y PAL, probably the same as for X
|
|
|
|
*/
|
|
|
|
char *gameid_to_cc(char *gameid)
|
|
{
|
|
// language codes:
|
|
//char *EN = "EN";
|
|
char *US = "US";
|
|
char *FR = "FR";
|
|
char *DE = "DE";
|
|
char *JA = "JA";
|
|
char *KO = "KO";
|
|
char *NL = "NL";
|
|
char *IT = "IT";
|
|
char *ES = "ES";
|
|
char *ZH = "ZH";
|
|
char *PAL = "PAL";
|
|
char *OTHER = "other";
|
|
// gameid regions:
|
|
switch (gameid[3]) {
|
|
// channel regions:
|
|
case 'A': return PAL;// All regions. System channels like the Mii channel use it.
|
|
case 'C': return US;
|
|
case 'D': return DE; // German-speaking regions.
|
|
case 'E': return US; // USA and other NTSC regions except Japan
|
|
case 'F': return FR; // French-speaking regions.
|
|
case 'J': return JA; // Japan
|
|
case 'K': return KO; // Korea
|
|
case 'L': return PAL;// Japanese Import to Europe, Australia and other PAL regions
|
|
case 'M': return PAL;// American Import to Europe, Australia and other PAL regions
|
|
case 'N': return US; // Japanese Import to USA and other NTSC regions
|
|
case 'P': return PAL;// Europe, Australia and other PAL regions
|
|
case 'Q': return KO; // Korea with Japanese language.
|
|
case 'T': return KO; // Korea with English language.
|
|
// game regions:
|
|
case 'H': return NL; // Netherlands
|
|
case 'I': return IT; // Italy
|
|
case 'S': return ES; // Spain
|
|
case 'X': return PAL;
|
|
case 'Y': return PAL;
|
|
case 'W': return ZH; // Taiwan
|
|
}
|
|
return OTHER;
|
|
}
|
|
|
|
char *lang_to_cc()
|
|
{
|
|
//printf("lang: %d\n", CONF_GetLanguage());
|
|
switch(CONF_GetLanguage()){
|
|
case CONF_LANG_JAPANESE: return "JA";
|
|
case CONF_LANG_ENGLISH: return "EN";
|
|
case CONF_LANG_GERMAN: return "DE";
|
|
case CONF_LANG_FRENCH: return "FR";
|
|
case CONF_LANG_SPANISH: return "ES";
|
|
case CONF_LANG_ITALIAN: return "IT";
|
|
case CONF_LANG_DUTCH: return "NL";
|
|
case CONF_LANG_KOREAN: return "KO";
|
|
case CONF_LANG_SIMP_CHINESE: return "ZHCN";
|
|
case CONF_LANG_TRAD_CHINESE: return "ZHTW";
|
|
}
|
|
return "EN";
|
|
}
|
|
|
|
char *auto_cc()
|
|
{
|
|
//printf("area: %d\n", CONF_GetArea());
|
|
switch(CONF_GetArea()){
|
|
case CONF_AREA_AUS: return "AU";
|
|
case CONF_AREA_BRA: return "PT";
|
|
}
|
|
return lang_to_cc();
|
|
}
|
|
|
|
char *get_cc()
|
|
{
|
|
if (*CFG.download_cc_pal) {
|
|
return CFG.download_cc_pal;
|
|
} else {
|
|
return auto_cc();
|
|
}
|
|
}
|
|
|
|
static bool fmt_cc_pal = false;
|
|
|
|
void format_URL(char *game_id, char *url, int size)
|
|
{
|
|
// widescreen
|
|
int width, height;
|
|
width = CFG.N_COVER_WIDTH;
|
|
height = CFG.N_COVER_HEIGHT;
|
|
// region
|
|
char region[10];
|
|
switch(game_id[3]){
|
|
case 'E':
|
|
sprintf(region,"ntsc");
|
|
break;
|
|
case 'J':
|
|
sprintf(region,"ntscj");
|
|
break;
|
|
default:
|
|
case 'P':
|
|
sprintf(region,"pal");
|
|
break;
|
|
}
|
|
// country code
|
|
fmt_cc_pal = false;
|
|
char *cc = gameid_to_cc(game_id);
|
|
if (strcmp(cc, "PAL") == 0) {
|
|
cc = get_cc();
|
|
if (strcmp(cc, "EN") != 0) {
|
|
fmt_cc_pal = true;
|
|
}
|
|
}
|
|
// set URL
|
|
char id[8];
|
|
char tmps[15];
|
|
STRCOPY(id, game_id);
|
|
str_replace(url, "{REGION}", region, size);
|
|
if (str_replace(url, "{CC}", cc, size) == false) fmt_cc_pal = false;
|
|
id[6] = 0;
|
|
str_replace(url, "{PUB}", id+4, size);
|
|
id[6] = 0;
|
|
str_replace(url, "{ID6}", id, size);
|
|
id[4] = 0;
|
|
str_replace(url, "{ID4}", id, size);
|
|
id[3] = 0;
|
|
str_replace(url, "{ID3}", id, size);
|
|
sprintf(tmps, "%d", width);
|
|
str_replace(url, "{WIDTH}", tmps, size);
|
|
sprintf(tmps, "%d", height);
|
|
str_replace(url, "{HEIGHT}", tmps, size);
|
|
|
|
dbg_printf("URL: %s\n", url);
|
|
}
|
|
|
|
struct block Download_URL(char *id, char *url_list, int style)
|
|
{
|
|
struct block file;
|
|
char *next_url;
|
|
char url_fmt[200];
|
|
char url[200];
|
|
int retry_cnt = 0;
|
|
int id_cnt;
|
|
int pal_cnt;
|
|
|
|
next_url = url_list;
|
|
|
|
retry_url:
|
|
|
|
next_url = split_token(url_fmt, next_url, ' ', sizeof(url_fmt));
|
|
|
|
pal_cnt = 0;
|
|
|
|
retry_cc_pal:
|
|
|
|
id_cnt = 3;
|
|
|
|
retry_id:
|
|
|
|
if (retry_cnt > 0) {
|
|
printf_(gt("Trying (url#%d) ..."), retry_cnt+1);
|
|
printf("\n");
|
|
}
|
|
|
|
STRCOPY(url, url_fmt);
|
|
|
|
if (pal_cnt) {
|
|
str_replace(url, "{CC}", "EN", sizeof(url));
|
|
}
|
|
|
|
if (strstr(url, "{ID}")) {
|
|
// {ID} auto retries with 6,4,3
|
|
switch (id_cnt) {
|
|
case 3:
|
|
str_replace(url, "{ID}", "{ID6}", sizeof(url));
|
|
break;
|
|
case 2:
|
|
str_replace(url, "{ID}", "{ID4}", sizeof(url));
|
|
break;
|
|
case 1:
|
|
str_replace(url, "{ID}", "{ID3}", sizeof(url));
|
|
break;
|
|
}
|
|
id_cnt--;
|
|
} else {
|
|
id_cnt = 0;
|
|
}
|
|
|
|
format_URL(id, url, sizeof(url));
|
|
|
|
if (url[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_("%.35s\n", url);
|
|
if (strlen(url) > 35) {
|
|
printf_("%.35s\n", url+35);
|
|
}
|
|
printf_("[");
|
|
__console_flush(0);
|
|
int chunk = 16;
|
|
if (style == CFG_COVER_STYLE_FULL) chunk = 32;
|
|
if (style == CFG_COVER_STYLE_HQ) chunk = 96;
|
|
file = downloadfile_progress(url, chunk);
|
|
printf("]");
|
|
__console_flush(0);
|
|
|
|
if (file.data == NULL || file.size == 0) {
|
|
//printf("%s\n", url);
|
|
printf("\n");
|
|
printf_(gt("Error: no data."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
//printf(gt("Size: %d "), file.size);
|
|
printf(" %d", file.size);
|
|
|
|
// verify if valid png
|
|
s32 ret;
|
|
u32 w, h;
|
|
ret = __Gui_GetPngDimensions(file.data, &w, &h);
|
|
if (ret) {
|
|
//printf("\n%s\n", url);
|
|
printf("\n");
|
|
printf_(gt("Error: Invalid PNG image!"));
|
|
printf("\n");
|
|
SAFE_FREE(file.data);
|
|
goto dl_err;
|
|
}
|
|
|
|
// success
|
|
goto out;
|
|
|
|
// error
|
|
dl_err:
|
|
retry_cnt++;
|
|
if (id_cnt > 0) goto retry_id;
|
|
if (fmt_cc_pal && pal_cnt == 0) {
|
|
pal_cnt++;
|
|
goto retry_cc_pal;
|
|
}
|
|
if (next_url) goto retry_url;
|
|
file.data = NULL;
|
|
file.size = 0;
|
|
out:
|
|
if (retry_cnt > 0) {
|
|
//sleep(2);
|
|
if (CFG.debug) { printf("Press any button.\n"); Wpad_WaitButtons(); }
|
|
}
|
|
__console_flush(0);
|
|
|
|
return file;
|
|
}
|
|
|
|
const char *get_style_name(int style)
|
|
{
|
|
switch (style) {
|
|
case CFG_COVER_STYLE_2D: return gt("FLAT cover");
|
|
case CFG_COVER_STYLE_3D: return gt("3D cover");
|
|
case CFG_COVER_STYLE_DISC: return gt("DISC cover");
|
|
case CFG_COVER_STYLE_FULL: return gt("FULL cover");
|
|
case CFG_COVER_STYLE_HQ: return gt("HQ cover");
|
|
}
|
|
return "?";
|
|
}
|
|
|
|
char* get_cover_url(int style)
|
|
{
|
|
switch (style) {
|
|
default:
|
|
case CFG_COVER_STYLE_2D:
|
|
return CFG.cover_url_2d;
|
|
|
|
case CFG_COVER_STYLE_3D:
|
|
return CFG.cover_url_3d;
|
|
|
|
case CFG_COVER_STYLE_DISC:
|
|
return CFG.cover_url_disc;
|
|
|
|
case CFG_COVER_STYLE_FULL:
|
|
return CFG.cover_url_full;
|
|
|
|
case CFG_COVER_STYLE_HQ:
|
|
return CFG.cover_url_hq;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bool Download_Cover_Style(char *id, int style)
|
|
{
|
|
char imgName[100];
|
|
char imgPath[100];
|
|
char *path = "";
|
|
char *url = "";
|
|
char *wide = "";
|
|
bool success = false;
|
|
struct stat st;
|
|
|
|
url = get_cover_url(style);
|
|
if (strlen(url) < 10) return false;
|
|
|
|
path = cfg_get_covers_path(style);
|
|
if (style == CFG_COVER_STYLE_2D && path == CFG.covers_path) {
|
|
if (stat(CFG.covers_path_2d, &st) == 0) {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
path = CFG.covers_path_2d;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CFG.download_id_len == 6) {
|
|
// save as 6 character ID
|
|
snprintf(imgName, sizeof(imgName), "%.6s%s.png", id, wide);
|
|
} else {
|
|
// save as 4 character ID
|
|
snprintf(imgName, sizeof(imgName), "%.4s%s.png", id, wide);
|
|
}
|
|
printf("[%.6s] : %s", id, get_style_name(style));
|
|
printf("\n");
|
|
|
|
if (strncmp(path, NTFS_DRIVE, strlen(NTFS_DRIVE)) == 0) {
|
|
if (CFG.ntfs_write == 0) {
|
|
void print_ntfs_write_error();
|
|
print_ntfs_write_error();
|
|
dl_abort = 1;
|
|
goto dl_err;
|
|
}
|
|
}
|
|
|
|
snprintf(imgPath, sizeof(imgPath), "%s/%s", path, imgName);
|
|
|
|
// try to download image
|
|
struct block file;
|
|
file = Download_URL(id, url, style);
|
|
if (file.data == NULL) {
|
|
goto dl_err;
|
|
}
|
|
|
|
// check path access
|
|
char drive_root[8];
|
|
snprintf(drive_root, sizeof(drive_root), "%s/", FAT_DRIVE);
|
|
if (stat(drive_root, &st)) {
|
|
printf_(gt("ERROR: %s is not accessible"), drive_root);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
if (stat(path, &st)) {
|
|
if (mkpath(path, 0777)) {
|
|
printf_(gt("Cannot create dir: %s"), path);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
}
|
|
|
|
// save png to sd card for future use
|
|
FILE *f;
|
|
f = fopen(imgPath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("ERROR: creating: %s"), imgPath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
int ret = fwrite(file.data,file.size,1,f);
|
|
fclose (f);
|
|
SAFE_FREE(file.data);
|
|
Cache_Invalidate_Cover((u8*)id, style);
|
|
if (ret != 1) {
|
|
printf(" ");
|
|
printf(gt("ERROR: writing %s (%d)."), imgPath, ret);
|
|
printf("\n");
|
|
remove(imgPath);
|
|
} else {
|
|
printf(" ");
|
|
//printf(gt("Download complete."));
|
|
printf(gt("OK"));
|
|
printf("\n\n");
|
|
success = true;
|
|
}
|
|
__console_flush(0);
|
|
|
|
//refresh = true;
|
|
//sleep(3);
|
|
return success;
|
|
|
|
dl_err:
|
|
__console_flush(0);
|
|
sleep(2);
|
|
if (CFG.debug) { printf(gt("Press any button...")); printf("\n"); Wpad_WaitButtons(); }
|
|
return false;
|
|
}
|
|
|
|
bool Download_Cover_Missing(char *id, int style, bool missing_only, bool verbose)
|
|
{
|
|
int ret;
|
|
void *data = NULL;
|
|
char path[200];
|
|
|
|
if (!id) return false;
|
|
|
|
if (missing_only) {
|
|
// check if missing
|
|
ret = Gui_LoadCover_style((u8*)id, &data, false, style, path);
|
|
if (ret > 0 && data) {
|
|
// found. verify if valid png
|
|
u32 width, height;
|
|
ret = __Gui_GetPngDimensions(data, &width, &height);
|
|
if (ret == 0 && width > 0 && height > 0) {
|
|
GRRLIB_texImg tx_tmp = Gui_LoadTexture_RGBA8(data, width, height, NULL, path);
|
|
bool found = false;
|
|
if (tx_tmp.data) found = true;
|
|
SAFE_FREE(data);
|
|
SAFE_FREE(tx_tmp.data);
|
|
if (style == CFG_COVER_STYLE_HQ) {
|
|
if (width <= 512) found = false;
|
|
}
|
|
if (found) {
|
|
if (verbose) {
|
|
printf_(gt("Found %s"), get_style_name(style));
|
|
printf("\n");
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Download_Cover_Style(id, style);
|
|
}
|
|
|
|
void Download_Cover(char *id, bool missing_only, bool verbose)
|
|
{
|
|
if (!id)
|
|
return;
|
|
|
|
if (strlen(id) < 4) {
|
|
printf(gt("ERROR: Invalid Game ID"));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
if (verbose) {
|
|
if (missing_only) {
|
|
printf_x(gt("Downloading MISSING covers for %.6s"), id);
|
|
} else {
|
|
printf_x(gt("Downloading ALL covers for %.6s"), id);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
//the first time no image is found, attempt to init network
|
|
if(!Init_Net()) goto dl_err;
|
|
if (verbose) printf("\n");
|
|
dl_abort = 0;
|
|
|
|
if (CFG.download_all) {
|
|
Download_Cover_Missing(id, CFG_COVER_STYLE_2D, missing_only, verbose);
|
|
Download_Cover_Missing(id, CFG_COVER_STYLE_3D, missing_only, verbose);
|
|
Download_Cover_Missing(id, CFG_COVER_STYLE_DISC, missing_only, verbose);
|
|
if (!Download_Cover_Missing(id, CFG_COVER_STYLE_HQ, missing_only, verbose)) {
|
|
Download_Cover_Missing(id, CFG_COVER_STYLE_FULL, missing_only, verbose);
|
|
}
|
|
} else {
|
|
if (gui_style == GUI_STYLE_COVERFLOW) {
|
|
// if in a coverflow GUI mode, download full covers.
|
|
// If full cover not found, download 2D.
|
|
if (!Download_Cover_Missing(id, CFG_COVER_STYLE_HQ, missing_only, verbose)) {
|
|
if (!Download_Cover_Missing(id, CFG_COVER_STYLE_FULL, missing_only, verbose)) {
|
|
Download_Cover_Missing(id, CFG_COVER_STYLE_2D, missing_only, verbose);
|
|
}
|
|
}
|
|
} else {
|
|
Download_Cover_Missing(id, CFG.cover_style, missing_only, verbose);
|
|
}
|
|
}
|
|
if (dl_abort) goto dl_err;
|
|
|
|
return;
|
|
dl_err:
|
|
sleep(3);
|
|
}
|
|
|
|
void Download_All_Covers(bool missing_only)
|
|
{
|
|
int i;
|
|
struct discHdr *header;
|
|
u32 buttons;
|
|
printf("\n");
|
|
if (missing_only) {
|
|
printf_x(gt("Downloading ALL MISSING covers"));
|
|
} else {
|
|
printf_x(gt("Downloading ALL covers"));
|
|
}
|
|
printf("\n\n");
|
|
printf_(gt("Hold button B to cancel."));
|
|
printf("\n\n");
|
|
//dbg_time1();
|
|
for (i=0; i<gameCnt; i++) {
|
|
buttons = Wpad_GetButtons();
|
|
if ((buttons & CFG.button_cancel.mask) || dl_abort) {
|
|
printf("\n");
|
|
printf_(gt("Cancelled."));
|
|
printf("\n");
|
|
sleep(1);
|
|
return;
|
|
}
|
|
header = &gameList[i];
|
|
printf("%d / %d %.4s %.25s\n", i+1, gameCnt, header->id, get_title(header));
|
|
__console_flush(0);
|
|
Gui_DrawCover(header->id);
|
|
Download_Cover((char*)header->id, missing_only, false);
|
|
Gui_DrawCover(header->id);
|
|
}
|
|
printf("\n");
|
|
printf_(gt("Done."));
|
|
printf("\n");
|
|
//unsigned ms = dbg_time2(NULL);
|
|
//printf_("Time: %.2f seconds\n", (float)ms/1000); Wpad_WaitButtons();
|
|
sleep(1);
|
|
}
|
|
|
|
|
|
/* download zipped XML - Lustar */
|
|
/* based on Download_Cover by Forsaeken, modified by oggzee */
|
|
void Download_XML()
|
|
{
|
|
|
|
printf("\n");
|
|
if(!Init_Net()) goto dl_err;
|
|
|
|
struct stat st;
|
|
char drive_root[8];
|
|
snprintf(drive_root, sizeof(drive_root), "%s/", FAT_DRIVE);
|
|
if (stat(drive_root, &st)) {
|
|
printf_(gt("ERROR: %s is not accessible"), drive_root);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
char zippath[200];
|
|
snprintf(zippath, sizeof(zippath), "%s/%s", USBLOADER_PATH, "wiitdb_new.zip");
|
|
char zipurl[100];
|
|
extern char *get_cc();
|
|
char *cc = get_cc();
|
|
char * dbl = ((strlen(CFG.db_language) == 2) ? VerifyLangCode(CFG.db_language) : ConvertLangTextToCode(CFG.db_language));
|
|
strcopy(zipurl, CFG.db_url, sizeof(zipurl));
|
|
str_replace(zipurl, "{CC}", cc, sizeof(zipurl));
|
|
str_replace(zipurl, "{DBL}", dbl, sizeof(zipurl));
|
|
|
|
if (zipurl[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
printf_x(gt("Downloading database."));
|
|
printf("\n");
|
|
printf_("%s\n", zipurl);
|
|
//goto skip_download;
|
|
printf_("[.");
|
|
struct block file = downloadfile_progress(zipurl, 64);
|
|
printf("]\n");
|
|
|
|
if (file.data == NULL) {
|
|
printf_(gt("Error: no data."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
printf_(gt("Size: %d bytes"), file.size);
|
|
printf("\n");
|
|
|
|
FILE *f;
|
|
f = fopen(zippath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), zippath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose (f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
/* try to open newly downloaded zipped XML */
|
|
printf_x(gt("Updating database."));
|
|
printf("\n");
|
|
|
|
//FreeXMLMemory();
|
|
char currentzippath[200];
|
|
snprintf(currentzippath, sizeof(currentzippath), "%s/wiitdb.zip", USBLOADER_PATH);
|
|
char tmppath[200];
|
|
snprintf(tmppath, sizeof(tmppath), "%s/wiitdb_old.zip", USBLOADER_PATH);
|
|
remove(tmppath);
|
|
rename(currentzippath, tmppath);
|
|
rename(zippath, currentzippath);
|
|
//skip_download:
|
|
if (ReloadXMLDatabase(USBLOADER_PATH, CFG.db_language, 0)) {
|
|
printf_(gt("Database update successful."));
|
|
printf("\n");
|
|
} else {
|
|
// revert to the previous file
|
|
// TODO File is to big to load on the fly need to free up 1 meg in mem2
|
|
// their is enough memory to load it on startup
|
|
// and it already displays a message telling user to restart to use the new file
|
|
// remove(currentzippath);
|
|
// rename(tmppath, currentzippath);
|
|
// ReloadXMLDatabase(USBLOADER_PATH, CFG.db_language, 0);
|
|
printf_(gt("Error opening database, update did not complete."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
__console_flush(0);
|
|
sleep(2);
|
|
return;
|
|
|
|
dl_err:
|
|
sleep(4);
|
|
} /* end download zipped xml */
|
|
|
|
/* download zipped Devolution - Lustar */
|
|
/* based on Download_Cover by Forsaeken, modified by oggzee */
|
|
void Download_Plugins()
|
|
{
|
|
|
|
printf("\n");
|
|
if(!Init_Net()) goto dl_err;
|
|
|
|
struct stat st;
|
|
char drive_root[8];
|
|
snprintf(drive_root, sizeof(drive_root), "%s/", FAT_DRIVE);
|
|
if (stat(drive_root, &st)) {
|
|
printf_(gt("ERROR: %s is not accessible"), drive_root);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
char zippath[200];
|
|
snprintf(zippath, sizeof(zippath), "%s/%s", USBLOADER_PATH, "devolution.zip");
|
|
remove(zippath);
|
|
char zipurl[100];
|
|
strcopy(zipurl, "http://www.tueidj.net/gc_devo_src.zip", sizeof(zipurl));
|
|
if (zipurl[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_x(gt("Downloading devolution."));
|
|
printf("\n");
|
|
printf_("%s\n", zipurl);
|
|
|
|
printf_("[.");
|
|
struct block file = downloadfile_progress(zipurl, 64);
|
|
printf("]\n");
|
|
|
|
if (file.data == NULL) {
|
|
printf_(gt("Error: no data."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
printf_(gt("Size: %d bytes"), file.size);
|
|
printf("\n");
|
|
|
|
FILE *f;
|
|
f = fopen(zippath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), zippath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose (f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
/* try to open newly downloaded zipped XML */
|
|
printf_x(gt("Updating devolution"));
|
|
printf("\n");
|
|
|
|
////////////////////////
|
|
unzFile unzfile = unzOpen(zippath);
|
|
if (unzfile == NULL) {
|
|
printf_(gt("Error opening: %s"), zippath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
u8 *buffer = NULL;
|
|
//unzOpenCurrentFile(unzfile);
|
|
unz_file_info zipfileinfo;
|
|
unzLocateFile(unzfile, "gc_devo/data/loader.bin", 0);
|
|
unzOpenCurrentFile(unzfile);
|
|
unzGetCurrentFileInfo(unzfile, &zipfileinfo, NULL, 0, NULL, 0, NULL, 0);
|
|
int zipfilebuffersize = zipfileinfo.uncompressed_size;
|
|
printf_(gt("loader.bin size: %d"), zipfilebuffersize);
|
|
printf("\n");
|
|
|
|
buffer = mem_calloc(zipfilebuffersize);
|
|
if (buffer == NULL) {
|
|
unzCloseCurrentFile(unzfile);
|
|
unzClose(unzfile);
|
|
printf_(gt("Error allocating buffer: %d"), zipfilebuffersize);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
unzReadCurrentFile(unzfile, buffer, zipfilebuffersize);
|
|
unzCloseCurrentFile(unzfile);
|
|
unzClose(unzfile);
|
|
|
|
char devopath[200];
|
|
snprintf(devopath, sizeof(zippath), "%s/%s", USBLOADER_PATH, "loader.bin");
|
|
remove(devopath);
|
|
|
|
f = fopen(devopath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), devopath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
printf_((char*)buffer+4);
|
|
fwrite(buffer,1,zipfilebuffersize,f);
|
|
fclose(f);
|
|
memset(buffer, 0, zipfilebuffersize);
|
|
SAFE_FREE(buffer);
|
|
///////////////////////
|
|
|
|
/* Download Mighty Plugin */
|
|
char mightyPath[200];
|
|
snprintf(mightyPath, sizeof(mightyPath), "%s/%s", USBLOADER_PATH, "/plugins");
|
|
if (!fsop_DirExist(mightyPath)) mkpath(mightyPath, 0777);
|
|
strcat(mightyPath, "/mighty.dol");
|
|
remove(mightyPath);
|
|
char url[255];
|
|
strcopy(url, "http://cfg-loader-mod.googlecode.com/files/mighty.dol", sizeof(url));
|
|
if (url[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_x(gt("Downloading mighty plugin."));
|
|
printf("\n");
|
|
printf_("%s\n", url);
|
|
|
|
printf_("[.");
|
|
file = downloadfile_progress(url, 64);
|
|
printf("]\n");
|
|
|
|
f = fopen(mightyPath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), mightyPath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose(f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
|
|
///////////////////////
|
|
|
|
/* Download Neek2o Plugin */
|
|
char neekPath[200];
|
|
snprintf(neekPath, sizeof(neekPath), "%s/%s", USBLOADER_PATH, "/plugins");
|
|
if (!fsop_DirExist(neekPath)) mkpath(neekPath, 0777);
|
|
strcat(neekPath, "/neek2o.dol");
|
|
remove(neekPath);
|
|
strcopy(url, "http://cfg-loader-mod.googlecode.com/files/neek2o.dol", sizeof(url));
|
|
if (url[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_x(gt("Downloading neek2o plugin."));
|
|
printf("\n");
|
|
printf_("%s\n", url);
|
|
|
|
printf_("[.");
|
|
file = downloadfile_progress(url, 64);
|
|
printf("]\n");
|
|
|
|
f = fopen(neekPath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), neekPath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose(f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
|
|
///////////////////////
|
|
__console_flush(0);
|
|
printf_x(gt("Press any button.\n"));
|
|
Wpad_WaitButtons();
|
|
return;
|
|
|
|
dl_err:
|
|
sleep(4);
|
|
} /* end download zipped devolution */
|
|
|
|
void Download_Translation()
|
|
{
|
|
char destPath[200];
|
|
char url[255];
|
|
struct block file;
|
|
FILE *f = NULL;
|
|
file.data = NULL;
|
|
|
|
printf("\n");
|
|
if(!Init_Net()) goto dl_err;
|
|
|
|
///////////////////////
|
|
|
|
/* Download unifont */
|
|
snprintf(destPath, sizeof(destPath), "%s", USBLOADER_PATH);
|
|
if (!fsop_DirExist(destPath)) mkpath(destPath, 0777);
|
|
strcat(destPath, "/unifont.dat");
|
|
if ((!CFG.load_unifont) || fsop_FileExist(destPath)) //if unifont not used or already exists
|
|
goto skip_unifont; //dont need to download it
|
|
strcopy(url, "http://cfg-loader-mod.googlecode.com/svn/trunk/tools/unifont.dat", sizeof(url));
|
|
if (url[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_x(gt("Downloading unifont."));
|
|
printf("\n");
|
|
printf_("%s\n", url);
|
|
|
|
printf_("[.");
|
|
file = downloadfile_progress(url, 64);
|
|
printf("]\n");
|
|
|
|
if (file.data == NULL || file.size < 1300000) {
|
|
goto dl_err;
|
|
}
|
|
|
|
remove(destPath);
|
|
|
|
f = fopen(destPath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), destPath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose(f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
skip_unifont:
|
|
///////////////////////
|
|
|
|
/* Download language file */
|
|
if (strcmp(CFG.translation, "EN") == 0) // if english
|
|
goto skip_language; // no file to download
|
|
snprintf(destPath, sizeof(destPath), "%s/%s", USBLOADER_PATH, "/languages");
|
|
if (!fsop_DirExist(destPath)) mkpath(destPath, 0777);
|
|
snprintf(destPath, sizeof(destPath), "%s/%s.lang", destPath, CFG.translation);
|
|
snprintf(url, sizeof(url), "http://cfg-loader-mod.googlecode.com/svn/trunk/Languages/%s.lang", CFG.translation);
|
|
if (url[0] == 0) {
|
|
printf_(gt("Error: no URL."));
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
|
|
printf_x(gt("Downloading translation file."));
|
|
printf("\n");
|
|
printf_("%s\n", url);
|
|
|
|
printf_("[.");
|
|
file = downloadfile_progress(url, 64);
|
|
printf("]\n");
|
|
|
|
size_t old_file_size;
|
|
fsop_GetFileSizeBytes (destPath, &old_file_size);
|
|
if (file.data == NULL || file.size < 30000 || old_file_size > file.size) {
|
|
goto dl_err;
|
|
}
|
|
|
|
// backup old language file
|
|
char bak_name[200];
|
|
strcpy(bak_name, destPath);
|
|
strcat(bak_name, ".bak");
|
|
// remove old backup
|
|
remove(bak_name);
|
|
// rename current to backup
|
|
rename(destPath, bak_name);
|
|
|
|
f = fopen(destPath, "wb");
|
|
if (!f) {
|
|
printf("\n");
|
|
printf_(gt("Error opening: %s"), destPath);
|
|
printf("\n");
|
|
goto dl_err;
|
|
}
|
|
fwrite(file.data,1,file.size,f);
|
|
fclose(f);
|
|
SAFE_FREE(file.data);
|
|
printf_(gt("Download complete."));
|
|
printf("\n");
|
|
|
|
skip_language:
|
|
///////////////////////
|
|
|
|
// __console_flush(0);
|
|
// printf_x(gt("Press any button.\n"));
|
|
// Wpad_WaitButtons();
|
|
return;
|
|
|
|
dl_err:
|
|
SAFE_FREE(file.data);
|
|
sleep(4);
|
|
}
|
|
|
|
int gamercard_enabled = 1;
|
|
|
|
int gamercard_update(char *ID)
|
|
{
|
|
if (!gamercard_enabled) return 0;
|
|
char *next_key, *next_url;
|
|
bool net_initted = false;
|
|
int gcard_cnt = 0;
|
|
int result = 0;
|
|
next_key = CFG.gamercard_key;
|
|
next_url = CFG.gamercard_url;
|
|
if (*next_key == 0 || *next_url == 0)
|
|
return 0;
|
|
while(next_key && next_url) {
|
|
char key[80];
|
|
char url[200];
|
|
next_key = split_token(key, next_key, ' ', sizeof(key));
|
|
next_url = split_token(url, next_url, ' ', sizeof(url));
|
|
gcard_cnt++;
|
|
if (strcmp(key, "0") == 0) {
|
|
continue;
|
|
}
|
|
|
|
if(!net_initted && !Init_Net()) {
|
|
printf_x(gt("Network error. Can't update gamercards."));
|
|
printf("\n");
|
|
return -1;
|
|
} else
|
|
net_initted = true;
|
|
|
|
str_replace(url, "{KEY}", key, sizeof(url));
|
|
str_replace(url, "{ID6}", ID, sizeof(url));
|
|
|
|
struct block file;
|
|
file = downloadfile(url);
|
|
if(file.data == NULL || file.size == 0) {
|
|
printf_x(gt("Download error on gamercard #%d."), gcard_cnt);
|
|
printf("\n");
|
|
result = -2;
|
|
} else {
|
|
printf_x(gt("Gamercard #%d reported: %.*s"), gcard_cnt, file.size,file.data);
|
|
printf("\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|