*Fixed crash on NTFS (wrong memory free functions were used)

*Added proper deinitialize of usb before starting game / exiting app. This is supposed to fix Blackops multiplayer mode (Did not test it. I don't have that game.)
*Added Wii message board update (Playlog) (thanks to dkosmari for a starting point). This feature can be enabled/disabled in the global settings. Default is ON.
*Removed unused sources.
This commit is contained in:
dimok321 2010-12-27 09:44:27 +00:00
parent d62e41d601
commit 6850d68074
19 changed files with 1271 additions and 613 deletions

File diff suppressed because one or more lines are too long

View File

@ -10,11 +10,13 @@
#include "settings/CGameSettings.h" #include "settings/CGameSettings.h"
#include "usbloader/frag.h" #include "usbloader/frag.h"
#include "usbloader/wbfs.h" #include "usbloader/wbfs.h"
#include "usbloader/playlog.h"
#include "settings/newtitles.h" #include "settings/newtitles.h"
#include "patches/fst.h" #include "patches/fst.h"
#include "patches/gamepatches.h" #include "patches/gamepatches.h"
#include "patches/wip.h" #include "patches/wip.h"
#include "system/IosLoader.h" #include "system/IosLoader.h"
#include "banner/OpeningBNR.hpp"
#include "wad/nandtitle.h" #include "wad/nandtitle.h"
#include "menu/menus.h" #include "menu/menus.h"
#include "memory/memory.h" #include "memory/memory.h"
@ -211,6 +213,10 @@ int BootGame(const char * gameID)
UnmountEXT(); UnmountEXT();
SDCard_deInit(); SDCard_deInit();
USBDevice_deInit(); USBDevice_deInit();
USB_Deinitialize();
if(Settings.PlaylogUpdate)
Playlog_Update((char *) Disc_ID, BNRInstance::Instance()->GetIMETTitle(CONF_GetLanguage()));
gprintf("Jumping to game entrypoint: 0x%08X.\n", AppEntrypoint); gprintf("Jumping to game entrypoint: 0x%08X.\n", AppEntrypoint);

View File

@ -0,0 +1,159 @@
#include <malloc.h>
#include <stdio.h>
#include "usbloader/disc.h"
#include "usbloader/wbfs.h"
#include "utils/uncompress.h"
#include "OpeningBNR.hpp"
typedef struct _IMD5Header
{
u32 fcc;
u32 filesize;
u8 zeroes[8];
u8 crypto[16];
} __attribute__((packed)) IMD5Header;
typedef struct _U8Header
{
u32 fcc;
u32 rootNodeOffset;
u32 headerSize;
u32 dataOffset;
u8 zeroes[16];
} __attribute__((packed)) U8Header;
typedef struct _U8Entry
{
struct
{
u32 fileType :8;
u32 nameOffset :24;
};
u32 fileOffset;
union
{
u32 fileLength;
u32 numEntries;
};
} __attribute__( ( packed ) ) U8Entry;
static inline const char * u8Filename(const U8Entry *fst, int i)
{
return (char *) (fst + fst[0].numEntries) + fst[i].nameOffset;
}
BNRInstance * BNRInstance::instance = NULL;
OpeningBNR::OpeningBNR()
: imetHdr(0)
{
memset(gameID, 0, sizeof(gameID));
}
OpeningBNR::~OpeningBNR()
{
if(imetHdr)
free(imetHdr);
}
bool OpeningBNR::Load(const u8 * discid)
{
if(!discid)
return false;
if(memcmp(gameID, discid, 6) == 0)
return true;
if(imetHdr)
free(imetHdr);
imetHdr = NULL;
snprintf(gameID, sizeof(gameID), (const char *) discid);
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) gameID);
if (!disc)
return false;
wiidisc_t *wdisc = wd_open_disc((int(*)(void *, u32, u32, void *)) wbfs_disc_read, disc);
if (!wdisc)
{
WBFS_CloseDisc(disc);
return false;
}
imetHdr = (IMETHeader*) wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr");
wd_close_disc(wdisc);
WBFS_CloseDisc(disc);
if(!imetHdr)
return false;
if (imetHdr->fcc != 'IMET')
{
free(imetHdr);
imetHdr = NULL;
return false;
}
return true;
}
const u16 * OpeningBNR::GetIMETTitle(int lang)
{
if(!imetHdr || lang < 0 || lang >= 10)
return NULL;
if(imetHdr->names[lang][0] == 0)
lang = CONF_LANG_ENGLISH;
return imetHdr->names[lang];
}
const u8 * OpeningBNR::GetBannerSound(u32 * size)
{
if(!imetHdr)
return NULL;
const U8Header *bnrArcHdr = (U8Header *) (imetHdr + 1);
const U8Entry *fst = (const U8Entry *) (((const u8 *) bnrArcHdr) + bnrArcHdr->rootNodeOffset);
u32 i;
for (i = 1; i < fst[0].numEntries; ++i)
if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0) break;
if (i >= fst[0].numEntries)
{
return NULL;
}
const u8 *sound_bin = ((const u8 *) bnrArcHdr) + fst[i].fileOffset;
if (((IMD5Header *) sound_bin)->fcc != 'IMD5')
{
return NULL;
}
const u8 *soundChunk = sound_bin + sizeof(IMD5Header);
u32 soundChunkSize = fst[i].fileLength - sizeof(IMD5Header);
if (*((u32*) soundChunk) == 'LZ77')
{
u32 uncSize = 0;
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, &uncSize);
if (!uncompressed_data)
{
return NULL;
}
if (size) *size = uncSize;
return uncompressed_data;
}
u8 *out = (u8 *) malloc(soundChunkSize);
if (out)
{
memcpy(out, soundChunk, soundChunkSize);
if (size) *size = soundChunkSize;
}
return out;
}

View File

@ -0,0 +1,46 @@
#ifndef OPENING_BNR_HPP_
#define OPENING_BNR_HPP_
#include <gctypes.h>
typedef struct _IMETHeader
{
u8 zeroes[64];
u32 fcc;
u8 unk[8];
u32 iconSize;
u32 bannerSize;
u32 soundSize;
u32 flag1;
u16 names[10][42]; // 10 languages (thanks dkosmari for the info)
u16 zeroes_2[7*42]; // padding for 7 more languages (thanks dkosmari for the info)
u8 crypto[16];
} __attribute__((packed)) IMETHeader;
class OpeningBNR
{
public:
OpeningBNR();
~OpeningBNR();
bool Load(const u8 * gameID);
const u16 * GetIMETTitle(int lang);
const u16 * GetIMETTitle(const u8 * gameID, int lang) { Load(gameID); return GetIMETTitle(lang); };
const u8 * GetBannerSound(u32 * size);
const u8 * GetBannerSound(const u8 * gameID, u32 * size) { Load(gameID); return GetBannerSound(size); };
private:
IMETHeader *imetHdr;
char gameID[7];
};
class BNRInstance : public OpeningBNR
{
public:
static BNRInstance * Instance() { if(!instance) instance = new BNRInstance; return instance; };
static void DestroyInstance() { delete instance; instance = NULL; };
private:
BNRInstance() { };
~BNRInstance() { };
static BNRInstance * instance;
};
#endif

View File

@ -1,562 +0,0 @@
/****************************************************************************
* USB Loader GX Team
* openingbnr
*
* Extract opening.bnr/banner.bin/sound.bin/icon.bin
*
* Copyright 2008 Magicus <magicus@gmail.com>
* Licensed under the terms of the GNU GPL, version 2
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
* Version 1.0 Initial release
***************************************************************************/
#define _GNU_SOURCE
#include <ogcsys.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fat.h>
#include "MD5.h"
#include "openingbnr.h"
#include "FileOperations/fileops.h"
u16 be16(const u8 *p)
{
return (p[0] << 8) | p[1];
}
u32 be32(const u8 *p)
{
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
}
u64 be64(const u8 *p)
{
return ((u64) be32(p) << 32) | be32(p + 4);
}
u64 be34(const u8 *p)
{
return 4 * (u64) be32(p);
}
void wbe16(u8 *p, u16 x)
{
p[0] = x >> 8;
p[1] = x;
}
void wbe32(u8 *p, u32 x)
{
wbe16(p, x >> 16);
wbe16(p + 2, x);
}
void wbe64(u8 *p, u64 x)
{
wbe32(p, x >> 32);
wbe32(p + 4, x);
}
void md5(u8 *data, u32 len, u8 *hash)
{
MD5(hash, data, len);
}
typedef struct
{
u8 zeroes[0x40];
u32 imet; // "IMET"
u8 zero_six_zero_three[8]; // fixed, unknown purpose
u32 sizes[3];
u32 flag1;
u16 name_jp[0x2a]; // might be empty
u16 name_en[0x2a];
u16 name_de[0x2a];
u16 name_fr[0x2a];
u16 name_es[0x2a];
u16 name_it[0x2a];
u16 name_nl[0x2a];
u8 zeroes_2[0x348];
u8 crypto[0x10];
} imet_data_t;
typedef struct
{
u32 imd5_tag; // 0x494D4435 "IMD5";
u32 size; // size of the rest of part B, starting from next field.
u8 zeroes[8];
u8 md5[16];
u32 payload_tag; // 0x4C5A3737 "LZ77" if this is lz77
u32 payload_data;
} imd5_header_t;
typedef struct
{
u16 type;
u16 name_offset;
u32 data_offset; // == absolut offset från U.8- headerns början
u32 size; // last included file num for directories
} U8_node;
typedef struct
{
u32 tag; // 0x55AA382D "U.8-"
u32 rootnode_offset; // offset to root_node, always 0x20.
u32 header_size; // size of header from root_node to end of string table.
u32 data_offset; // offset to data -- this is rootnode_offset + header_size, aligned to 0x40.
u8 zeroes[16];
} U8_archive_header;
static int write_file(void* data, size_t size, char* name)
{
size_t written = 0;
FILE *out;
out = fopen(name, "wb");
if (out)
{
written = fwrite(data, 1, size, out);
fclose(out);
}
return (written == size) ? 1 : -1;
}
u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
{
u8 *data_end;
u8 *decompressed_data;
size_t unpacked_size;
u8 *in_ptr;
u8 *out_ptr;
u8 *out_end;
in_ptr = data;
data_end = data + data_size;
// Assume this for now and grow when needed
unpacked_size = data_size;
decompressed_data = malloc(unpacked_size);
out_end = decompressed_data + unpacked_size;
out_ptr = decompressed_data;
while (in_ptr < data_end)
{
int bit;
u8 bitmask = *in_ptr;
in_ptr++;
for (bit = 0x80; bit != 0; bit >>= 1)
{
if (bitmask & bit)
{
// Next section is compressed
u8 rep_length;
u16 rep_offset;
rep_length = (*in_ptr >> 4) + 3;
rep_offset = *in_ptr & 0x0f;
in_ptr++;
rep_offset = *in_ptr | (rep_offset << 8);
in_ptr++;
if (out_ptr - decompressed_data < rep_offset)
{
return NULL;
}
for (; rep_length > 0; rep_length--)
{
*out_ptr = out_ptr[-rep_offset - 1];
out_ptr++;
if (out_ptr >= out_end)
{
// Need to grow buffer
decompressed_data = realloc(decompressed_data, unpacked_size * 2);
out_ptr = decompressed_data + unpacked_size;
unpacked_size *= 2;
out_end = decompressed_data + unpacked_size;
}
}
}
else
{
// Just copy byte
*out_ptr = *in_ptr;
out_ptr++;
if (out_ptr >= out_end)
{
// Need to grow buffer
decompressed_data = realloc(decompressed_data, unpacked_size * 2);
out_ptr = decompressed_data + unpacked_size;
unpacked_size *= 2;
out_end = decompressed_data + unpacked_size;
}
in_ptr++;
}
}
}
*decompressed_size = (out_ptr - decompressed_data);
return decompressed_data;
}
static int write_imd5_lz77(u8* data, size_t size, char* outname)
{
imd5_header_t* header = (imd5_header_t*) data;
u32 tag;
u32 size_in_imd5;
u8 md5_calc[16];
u8 *decompressed_data;
size_t decompressed_size;
tag = be32((u8*) &header->imd5_tag);
if (tag != 0x494D4435)
{
return -4;
}
md5(data + 32, size - 32, md5_calc);
if (memcmp(&header->md5, md5_calc, 0x10))
{
return -5;
}
size_in_imd5 = be32((u8*) &header->size);
if (size_in_imd5 != size - 32)
{
return -6;
}
tag = be32((u8*) &header->payload_tag);
if (tag == 0x4C5A3737)
{
// "LZ77" - uncompress
decompressed_data = decompress_lz77(data + sizeof(imd5_header_t), size - sizeof(imd5_header_t),
&decompressed_size);
if (decompressed_data == NULL) return -7;
write_file(decompressed_data, decompressed_size, outname);
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
free(decompressed_data);
}
else
{
write_file(&header->payload_tag, size - 32, outname);
//printf(", md5 ok");
}
return 0;
}
static int do_U8_archive(FILE *fp)
{
U8_archive_header header;
U8_node root_node;
u32 tag;
u32 num_nodes;
U8_node* nodes;
u8* string_table;
size_t rest_size;
unsigned int i;
u32 data_offset;
u32 current_offset;
u16 dir_stack[16];
int dir_index = 0;
fread(&header, 1, sizeof header, fp);
tag = be32((u8*) &header.tag);
if (tag != 0x55AA382D)
{
return -1;
}
fread(&root_node, 1, sizeof(root_node), fp);
num_nodes = be32((u8*) &root_node.size) - 1;
//printf("Number of files: %d\n", num_nodes);
nodes = malloc(sizeof(U8_node) * (num_nodes));
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
data_offset = be32((u8*) &header.data_offset);
rest_size = data_offset - sizeof(header) - (num_nodes + 1) * sizeof(U8_node);
string_table = malloc(rest_size);
fread(string_table, 1, rest_size, fp);
current_offset = data_offset;
for (i = 0; i < num_nodes; i++)
{
U8_node* node = &nodes[i];
u16 type = be16((u8*) &node->type);
u16 name_offset = be16((u8*) &node->name_offset);
u32 my_data_offset = be32((u8*) &node->data_offset);
u32 size = be32((u8*) &node->size);
char* name = (char*) &string_table[name_offset];
u8* file_data;
if (type == 0x0100)
{
// Directory
mkdir(name, 0777);
chdir(name);
dir_stack[++dir_index] = size;
//printf("%*s%s/\n", dir_index, "", name);
}
else
{
// Normal file
u8 padding[32];
if (type != 0x0000)
{
free(string_table);
return -2;
}
if (current_offset < my_data_offset)
{
int diff = my_data_offset - current_offset;
if (diff > 32)
{
free(string_table);
return -3;
}
fread(padding, 1, diff, fp);
current_offset += diff;
}
file_data = malloc(size);
fread(file_data, 1, size, fp);
//printf("%*s %s (%d bytes", dir_index, "", name, size);
int result;
result = write_imd5_lz77(file_data, size, name);
if (result < 0)
{
free(string_table);
return result;
}
//printf(")\n");
current_offset += size;
}
while (dir_stack[dir_index] == i + 2 && dir_index > 0)
{
chdir("..");
dir_index--;
}
}
free(string_table);
return 0;
}
static void do_imet_header(FILE *fp)
{
imet_data_t header;
fread(&header, 1, sizeof header, fp);
write_file(&header, sizeof(header), "header.imet");
}
void do_U8_archivebanner(FILE *fp)
{
U8_archive_header header;
U8_node root_node;
u32 tag;
u32 num_nodes;
U8_node* nodes;
u8* string_table;
size_t rest_size;
unsigned int i;
u32 data_offset;
u16 dir_stack[16];
int dir_index = 0;
fread(&header, 1, sizeof header, fp);
tag = be32((u8*) &header.tag);
if (tag != 0x55AA382D)
{
//printf("No U8 tag");
exit(0);
}
fread(&root_node, 1, sizeof(root_node), fp);
num_nodes = be32((u8*) &root_node.size) - 1;
printf("Number of files: %d\n", num_nodes);
nodes = malloc(sizeof(U8_node) * (num_nodes));
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
data_offset = be32((u8*) &header.data_offset);
rest_size = data_offset - sizeof(header) - (num_nodes + 1) * sizeof(U8_node);
string_table = malloc(rest_size);
fread(string_table, 1, rest_size, fp);
for (i = 0; i < num_nodes; i++)
{
U8_node* node = &nodes[i];
u16 type = be16((u8*) &node->type);
u16 name_offset = be16((u8*) &node->name_offset);
u32 my_data_offset = be32((u8*) &node->data_offset);
u32 size = be32((u8*) &node->size);
char* name = (char*) &string_table[name_offset];
u8* file_data;
if (type == 0x0100)
{
// Directory
mkdir(name, 0777);
chdir(name);
dir_stack[++dir_index] = size;
//printf("%*s%s/\n", dir_index, "", name);
}
else
{
// Normal file
if (type != 0x0000)
{
printf("Unknown type");
exit(0);
}
fseek(fp, my_data_offset, SEEK_SET);
file_data = malloc(size);
fread(file_data, 1, size, fp);
write_file(file_data, size, name);
free(file_data);
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
}
while (dir_stack[dir_index] == i + 2 && dir_index > 0)
{
chdir("..");
dir_index--;
}
}
free(string_table);
}
int extractbnrfile(const char * filepath, const char * destpath)
{
int ret = -1;
FILE *fp = fopen(filepath, "rb");
if (fp)
{
CreateSubfolder(destpath);
chdir(destpath);
do_imet_header(fp);
ret = do_U8_archive(fp);
fclose(fp);
}
return ret;
}
int unpackBin(const char * filename, const char * outdir)
{
FILE *fp = fopen(filename, "rb");
;
if (fp)
{
CreateSubfolder(outdir);
chdir(outdir);
do_U8_archivebanner(fp);
fclose(fp);
return 1;
}
return 0;
}
#if 0
#define TMP_PATH(s) "BANNER:/dump"s
//#define TMP_PATH(s) "SD:/dump"s
int unpackBanner(const u8 *gameid, int what, const char *outdir)
{
char path[256];
if (!ramdiskMount("BANNER", NULL)) return -1;
CreateSubfolder(TMP_PATH( "/" ));
s32 ret = dump_banner(gameid, TMP_PATH( "/opening.bnr" ));
if (ret != 1)
{
ret = -1;
goto error2;
}
ret = extractbnrfile(TMP_PATH( "/opening.bnr" ), TMP_PATH( "/" ));
if (ret != 0)
{
ret = -1;
goto error2;
}
if (what & UNPACK_BANNER_BIN)
{
snprintf(path, sizeof(path), "%sbanner/", outdir);
ret = unpackBin(TMP_PATH( "/meta/banner.bin" ), path);
if (ret != 1)
{
ret = -1;
goto error2;
}
}
if (what & UNPACK_ICON_BIN)
{
snprintf(path, sizeof(path), "%sicon/", outdir);
ret = unpackBin(TMP_PATH( "/meta/icon.bin" ), path);
if (ret != 1)
{
ret = -1;
goto error2;
}
}
if (what & UNPACK_SOUND_BIN)
{
snprintf(path, sizeof(path), "%ssound.bin", outdir);
FILE *fp = fopen(TMP_PATH( "/meta/sound.bin" ), "rb");
if (fp)
{
size_t size;
u8 *data;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
if (!size)
{
ret = -1;
goto error;
}
fseek(fp, 0, SEEK_SET);
data = (u8 *) malloc(size);
if (!data)
{
ret = -1;
goto error;
}
if (fread(data, 1, size, fp) != size)
{
ret = -1;
goto error;
}
ret = write_file(data, size, path);
}
error: fclose(fp);
}
ramdiskUnmount("BANNER");
error2: if (ret < 0) return ret;
return 1;
}
#endif

View File

@ -1,47 +0,0 @@
/****************************************************************************
* USB Loader GX Team
* openingbnr
*
* Extract opening.bnr/banner.bin/sound.bin/icon.bin
***************************************************************************/
#ifndef _OPENINGBNR_H_
#define _OPENINGBNR_H_
#ifdef __cplusplus
extern "C"
{
#endif
/***********************************************************
* Error description:
* 0 Successfully extracted
* -1 No U8 tag
* -2 Unknown type
* -3 Archive inconsistency, too much padding
* -4 No IMD5 tag
* -5 MD5 mismatch
* -6 Size mismatch
* -7 Inconsistency in LZ77 encoding
************************************************************/
//! Extract opening.bnr from filepath to destpath
//! Files extracted: banner.bin icon.bin and sound.bin
int extractbnrfile(const char * filepath, const char * destpath);
int unpackBin(const char * filename, const char * outdir);
#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */
#define UNPACK_ICON_BIN 2 /* extract icon.bin to outdir/icon/ */
#define UNPACK_SOUND_BIN 4 /* copies sound.bin to outdir/sound.bin */
#define UNPACK_ALL (UNPACK_SOUND_BIN | UNPACK_ICON_BIN | UNPACK_BANNER_BIN)
//int unpackBanner(const u8 * gameid, int what, const char *outdir);
//! Extract the lz77 compressed banner, icon and sound .bin
u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size);
u16 be16(const u8 *p);
u32 be32(const u8 *p);
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

View File

@ -12,7 +12,7 @@
#include "prompts/PromptWindows.h" #include "prompts/PromptWindows.h"
#include "language/gettext.h" #include "language/gettext.h"
#include "menu/menus.h" #include "menu/menus.h"
#include "bannersound.h" #include "banner/OpeningBNR.hpp"
#define NONE 0 #define NONE 0
#define LEFT 1 #define LEFT 1
@ -272,7 +272,7 @@ void GameWindow::LoadGameSound(const u8 * id)
} }
u32 gameSoundDataLen; u32 gameSoundDataLen;
const u8 *gameSoundData = LoadBannerSound(id, &gameSoundDataLen); const u8 *gameSoundData = BNRInstance::Instance()->GetBannerSound(id, &gameSoundDataLen);
if (gameSoundData) if (gameSoundData)
{ {
gameSound = new GuiSound(gameSoundData, gameSoundDataLen, Settings.gamesoundvolume, true); gameSound = new GuiSound(gameSoundData, gameSoundDataLen, Settings.gamesoundvolume, true);

View File

@ -42,7 +42,6 @@
#include "language/UpdateLanguage.h" #include "language/UpdateLanguage.h"
#include "gecko.h" #include "gecko.h"
#include "lstub.h" #include "lstub.h"
#include "bannersound.h"
#include "buildtype.h" #include "buildtype.h"
/*** Extern variables ***/ /*** Extern variables ***/

View File

@ -105,6 +105,7 @@ void CSettings::SetDefault()
FatInstallToDir = 0; FatInstallToDir = 0;
InstallPartitions = ONLY_GAME_PARTITION; InstallPartitions = ONLY_GAME_PARTITION;
beta_upgrades = 0; beta_upgrades = 0;
PlaylogUpdate = 1;
widescreen = (CONF_GetAspectRatio() == CONF_ASPECT_16_9); widescreen = (CONF_GetAspectRatio() == CONF_ASPECT_16_9);
Theme::SetDefault(); //! We need to move this later Theme::SetDefault(); //! We need to move this later
@ -213,6 +214,7 @@ bool CSettings::Save()
fprintf(file, "FatInstallToDir = %d\n ", FatInstallToDir); fprintf(file, "FatInstallToDir = %d\n ", FatInstallToDir);
fprintf(file, "InstallPartitions = %08X\n ", InstallPartitions); fprintf(file, "InstallPartitions = %08X\n ", InstallPartitions);
fprintf(file, "beta_upgrades = %d\n ", beta_upgrades); fprintf(file, "beta_upgrades = %d\n ", beta_upgrades);
fprintf(file, "PlaylogUpdate = %d\n ", PlaylogUpdate);
fprintf(file, "returnTo = %s\n ", returnTo); fprintf(file, "returnTo = %s\n ", returnTo);
fclose(file); fclose(file);
@ -441,6 +443,11 @@ bool CSettings::SetSetting(char *name, char *value)
if (sscanf(value, "%d", &i) == 1) beta_upgrades = i; if (sscanf(value, "%d", &i) == 1) beta_upgrades = i;
return true; return true;
} }
else if (strcmp(name, "PlaylogUpdate") == 0)
{
if (sscanf(value, "%d", &i) == 1) PlaylogUpdate = i;
return true;
}
else if (strcmp(name, "InstallPartitions") == 0) else if (strcmp(name, "InstallPartitions") == 0)
{ {
InstallPartitions = strtoul(value, 0, 16); InstallPartitions = strtoul(value, 0, 16);

View File

@ -108,6 +108,7 @@ class CSettings
short FatInstallToDir; short FatInstallToDir;
u32 InstallPartitions; u32 InstallPartitions;
short beta_upgrades; short beta_upgrades;
short PlaylogUpdate;
char returnTo[20]; char returnTo[20];
protected: protected:
bool SetSetting(char *name, char *value); bool SetSetting(char *name, char *value);

View File

@ -115,6 +115,7 @@ GameLoadSM::GameLoadSM()
Options->SetName(Idx++, "%s", tr( "Error 002 fix" )); Options->SetName(Idx++, "%s", tr( "Error 002 fix" ));
Options->SetName(Idx++, "%s", tr( "Install partitions" )); Options->SetName(Idx++, "%s", tr( "Install partitions" ));
Options->SetName(Idx++, "%s", tr( "Return To" )); Options->SetName(Idx++, "%s", tr( "Return To" ));
Options->SetName(Idx++, "%s", tr( "Messageboard Update" ));
SetOptionValues(); SetOptionValues();
@ -195,6 +196,9 @@ void GameLoadSM::SetOptionValues()
TitleName = NandTitles.NameFromIndex(haveTitle); TitleName = NandTitles.NameFromIndex(haveTitle);
TitleName = TitleName ? TitleName : strlen(Settings.returnTo) > 0 ? Settings.returnTo : tr(OnOffText[0]); TitleName = TitleName ? TitleName : strlen(Settings.returnTo) > 0 ? Settings.returnTo : tr(OnOffText[0]);
Options->SetValue(Idx++, "%s", TitleName); Options->SetValue(Idx++, "%s", TitleName);
//! Settings: Messageboard Update
Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.PlaylogUpdate] ));
} }
int GameLoadSM::GetMenuInternal() int GameLoadSM::GetMenuInternal()
@ -320,6 +324,12 @@ int GameLoadSM::GetMenuInternal()
snprintf(Settings.returnTo, sizeof(Settings.returnTo), "%s", tidChar); snprintf(Settings.returnTo, sizeof(Settings.returnTo), "%s", tidChar);
} }
//! Settings: Messageboard Update
else if (ret == ++Idx )
{
if (++Settings.PlaylogUpdate >= MAX_ON_OFF) Settings.PlaylogUpdate = 0;
}
SetOptionValues(); SetOptionValues();
return MENU_NONE; return MENU_NONE;

View File

@ -8,6 +8,7 @@
#include "language/gettext.h" #include "language/gettext.h"
#include "network/networkops.h" #include "network/networkops.h"
#include "utils/ResourceManager.h" #include "utils/ResourceManager.h"
#include "usbloader/playlog.h"
#include "FontSystem.h" #include "FontSystem.h"
#include "audio.h" #include "audio.h"
#include "fatmounter.h" #include "fatmounter.h"
@ -97,6 +98,9 @@ void ExitApp(void)
UnmountEXT(); UnmountEXT();
SDCard_deInit(); SDCard_deInit();
USBDevice_deInit(); USBDevice_deInit();
USB_Deinitialize();
if(Settings.PlaylogUpdate)
Playlog_Delete(); // Don't show USB Loader GX in the Wii message board
} }
void Sys_Reboot(void) void Sys_Reboot(void)

163
source/usbloader/playlog.c Normal file
View File

@ -0,0 +1,163 @@
/*
PLAYLOG.C
This code allows to modify play_rec.dat in order to store the
game time in Wii's log correctly.
by Marc
Thanks to tueidj for giving me some hints on how to do it :)
Most of the code was taken from here:
http://forum.wiibrew.org/read.php?27,22130
Modified by Dimok
*/
#include <stdio.h>
#include <string.h>
#include <ogcsys.h>
#include <malloc.h>
#include "gecko.h"
#include "utils/tools.h"
#define SECONDS_TO_2000 946684800LL
#define TICKS_PER_SECOND 60750000LL
//! Should be 32 byte aligned
static const char PLAYRECPATH[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/play_rec.dat";
typedef struct _PlayRec
{
u32 checksum;
union
{
u32 data[31];
struct
{
u16 name[42];
u64 ticks_boot;
u64 ticks_last;
char title_id[6];
char unknown[18];
} ATTRIBUTE_PACKED;
};
} PlayRec;
// Thanks to Dr. Clipper
static u64 getWiiTime(void)
{
time_t uTime = time(NULL);
return TICKS_PER_SECOND * (uTime - SECONDS_TO_2000);
}
int Playlog_Create(void)
{
s32 fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW);
if(fd >= 0)
{
//exists
IOS_Close(fd);
return 0;
}
ISFS_Initialize();
//In case the play_rec.dat wasn´t found create one and try again
int ret = ISFS_CreateFile(PLAYRECPATH, 0, 3, 3, 3);
if(ret >= 0)
ISFS_SetAttr(PLAYRECPATH, 0x1000, 1, 0, 3, 3, 3);
ISFS_Deinitialize();
return ret;
}
int Playlog_Update(const char * ID, const u16 * title)
{
if(!ID || !title)
return -1;
s32 fd = -1, res = -1;
u32 sum = 0;
u8 i;
//Open play_rec.dat
fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW);
if(fd == -106)
{
//In case the play_rec.dat wasn´t found create one and try again
int ret = Playlog_Create();
if(ret < 0)
return ret;
fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW);
}
if(fd < 0)
return res;
PlayRec * playrec_buf = memalign(32, ALIGN32(sizeof(PlayRec))); //! Should be 32 byte aligned
if(!playrec_buf)
{
IOS_Close(fd);
return res;
}
memset(playrec_buf, 0, sizeof(PlayRec));
u64 stime = getWiiTime();
playrec_buf->ticks_boot = stime;
playrec_buf->ticks_last = stime;
//Update channel name and ID
memcpy(playrec_buf->name, title, 84);
memcpy(playrec_buf->title_id, ID, 6);
//Calculate and update checksum
for(i = 0; i < 31; i++)
sum += playrec_buf->data[i];
playrec_buf->checksum = sum;
//Write play_rec.dat
if(IOS_Write(fd, playrec_buf, sizeof(PlayRec)) == sizeof(PlayRec))
res = 0;
IOS_Close(fd);
free(playrec_buf);
return res;
}
int Playlog_Delete(void)
{
s32 res = -1;
//Open play_rec.dat
s32 fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW);
if(fd < 0)
return fd;
PlayRec * playrec_buf = memalign(32, ALIGN32(sizeof(PlayRec)));
if(!playrec_buf)
goto cleanup;
//Read play_rec.dat
if(IOS_Read(fd, playrec_buf, sizeof(PlayRec)) != sizeof(PlayRec))
goto cleanup;
if(IOS_Seek(fd, 0, 0) < 0)
goto cleanup;
// invalidate checksum
playrec_buf->checksum = 0;
if(IOS_Write(fd, playrec_buf, sizeof(PlayRec)) != sizeof(PlayRec))
goto cleanup;
res = 0;
cleanup:
free(playrec_buf);
IOS_Close(fd);
return res;
}

View File

@ -0,0 +1,18 @@
#ifndef PLAYLOG_H_
#define PLAYLOG_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <gctypes.h>
int Playlog_Create(void);
int Playlog_Update(const char * ID, const u16 * title);
int Playlog_Delete(void);
#ifdef __cplusplus
}
#endif
#endif

608
source/utils/MD5.c Normal file
View File

@ -0,0 +1,608 @@
/* ========================================================================== **
*
* MD5.c
*
* Copyright:
* Copyright (C) 2003-2005 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: MD5.c,v 0.6 2005/06/08 18:35:59 crh Exp $
*
*
* Modifications and additions by dimok
*
* -------------------------------------------------------------------------- **
*
* Description:
* Implements the MD5 hash algorithm, as described in RFC 1321.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* None of this will make any sense unless you're studying RFC 1321 as you
* read the code.
*
* MD5 is described in RFC 1321.
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
* MD5 is very similar to MD4, but not quite similar enough to justify
* putting the two into a single module. Besides, I wanted to add a few
* extra functions to this one to expand its usability.
*
* There are three primary motivations for this particular implementation.
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
* wanted to learn from the experience.
* 2) Portability. I wanted an implementation that I knew to be portable
* to a reasonable number of platforms. In particular, the algorithm is
* designed with little-endian platforms in mind, but I wanted an
* endian-agnostic implementation.
* 3) Compactness. While not an overriding goal, I thought it worth-while
* to see if I could reduce the overall size of the result. This is in
* keeping with my hopes that this library will be suitable for use in
* some embedded environments.
* Beyond that, cleanliness and clarity are always worth pursuing.
*
* As mentioned above, the code really only makes sense if you are familiar
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
* quirky, however, so you'll want to be reading carefully.
*
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
*
* -------------------------------------------------------------------------- **
*
* References:
* IETF RFC 1321: The MD5 Message-Digest Algorithm
* Ron Rivest. IETF, April, 1992
*
* ========================================================================== **
*/
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include "MD5.h"
/* -------------------------------------------------------------------------- **
* Static Constants:
*
* K[][] - In round one, the values of k (which are used to index
* particular four-byte sequences in the input) are simply
* sequential. In later rounds, however, they are a bit more
* varied. Rather than calculate the values of k (which may
* or may not be possible--I haven't though about it) the
* values are stored in this array.
*
* S[][] - In each round there is a left rotate operation performed as
* part of the 16 permutations. The number of bits varies in
* a repeating patter. This array keeps track of the patterns
* used in each round.
*
* T[][] - There are four rounds of 16 permutations for a total of 64.
* In each of these 64 permutation operations, a different
* constant value is added to the mix. The constants are
* based on the sine function...read RFC 1321 for more detail.
* In any case, the correct constants are stored in the T[][]
* array. They're divided up into four groups of 16.
*/
static const uint8_t K[3][16] = {
/* Round 1: skipped (since it is simply sequential). */
{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, /* R2 */
{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, /* R3 */
{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */
};
static const uint8_t S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */
{ 5, 9, 14, 20 }, /* Round 2 */
{ 4, 11, 16, 23 }, /* Round 3 */
{ 6, 10, 15, 21 } /* Round 4 */
};
static const uint32_t T[4][16] = { { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
0xa679438e, 0x49b40821 },
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a },
{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5,
0x1fa27cf8, 0xc4ac5665 },
{ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,
0x2ad7d2bb, 0xeb86d391 }, };
/* -------------------------------------------------------------------------- **
* Macros:
* md5F(), md5G(), md5H(), and md5I() are described in RFC 1321.
* All of these operations are bitwise, and so not impacted by endian-ness.
*
* GetLongByte()
* Extract one byte from a (32-bit) longword. A value of 0 for <idx>
* indicates the lowest order byte, while 3 indicates the highest order
* byte.
*
*/
#define md5F( X, Y, Z ) ( ((X) & (Y)) | ((~(X)) & (Z)) )
#define md5G( X, Y, Z ) ( ((X) & (Z)) | ((Y) & (~(Z))) )
#define md5H( X, Y, Z ) ( (X) ^ (Y) ^ (Z) )
#define md5I( X, Y, Z ) ( (Y) ^ ((X) | (~(Z))) )
#define GetLongByte( L, idx ) ((unsigned char)(( L >> (((idx) & 0x03) << 3) ) & 0xFF))
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
/* -------------------------------------------------------------------------- **
* Static Functions:
*/
static void Permute(uint32_t ABCD[4], const unsigned char block[64])
/* ------------------------------------------------------------------------ **
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
*
* Input: ABCD - Pointer to an array of four unsigned longwords.
* block - An array of bytes, 64 bytes in size.
*
* Output: none.
*
* Notes: The MD5 algorithm operates on a set of four longwords stored
* (conceptually) in four "registers". It is easy to imagine a
* simple MD4/5 chip that would operate this way. In any case,
* the mangling of the contents of those registers is driven by
* the input message. The message is chopped and finally padded
* into 64-byte chunks and each chunk is used to manipulate the
* contents of the registers.
*
* The MD5 Algorithm calls for padding the input to ensure that
* it is a multiple of 64 bytes in length. The last 16 bytes
* of the padding space are used to store the message length
* (the length of the original message, before padding, expressed
* in terms of bits). If there is not enough room for 16 bytes
* worth of bitcount (eg., if the original message was 122 bytes
* long) then the block is padded to the end with zeros and
* passed to this function. Then *another* block is filled with
* zeros except for the last 16 bytes which contain the length.
*
* Oh... and the algorithm requires that there be at least one
* padding byte. The first padding byte has a value of 0x80,
* and any others are 0x00.
*
* ------------------------------------------------------------------------ **
*/
{
int round;
int i, j;
uint8_t s;
uint32_t a, b, c, d;
uint32_t KeepABCD[4];
uint32_t X[16];
/* Store the current ABCD values for later re-use.
*/
for (i = 0; i < 4; i++)
KeepABCD[i] = ABCD[i];
/* Convert the input block into an array of unsigned longs, taking care
* to read the block in Little Endian order (the algorithm assumes this).
* The uint32_t values are then handled in host order.
*/
for (i = 0, j = 0; i < 16; i++)
{
X[i] = (uint32_t) block[j++];
X[i] |= ((uint32_t) block[j++] << 8);
X[i] |= ((uint32_t) block[j++] << 16);
X[i] |= ((uint32_t) block[j++] << 24);
}
/* This loop performs the four rounds of permutations.
* The rounds are each very similar. The differences are in three areas:
* - The function (F, G, H, or I) used to perform bitwise permutations
* on the registers,
* - The order in which values from X[] are chosen.
* - Changes to the number of bits by which the registers are rotated.
* This implementation uses a switch statement to deal with some of the
* differences between rounds. Other differences are handled by storing
* values in arrays and using the round number to select the correct set
* of values.
*
* (My implementation appears to be a poor compromise between speed, size,
* and clarity. Ugh. [crh])
*/
for (round = 0; round < 4; round++)
{
for (i = 0; i < 16; i++)
{
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
s = S[round][i % 4]; /* <s> is the bit shift for this iteration. */
b = ABCD[(j + 1) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */
c = ABCD[(j + 2) & 0x3]; /* This isn't really necessary, it just looks */
d = ABCD[(j + 3) & 0x3]; /* clean & will hopefully be optimized away. */
/* The actual perumation function.
* This is broken out to minimize the code within the switch().
*/
switch (round)
{
case 0:
/* round 1 */
a = md5F( b, c, d ) + X[i];
break;
case 1:
/* round 2 */
a = md5G( b, c, d ) + X[K[0][i]];
break;
case 2:
/* round 3 */
a = md5H( b, c, d ) + X[K[1][i]];
break;
default:
/* round 4 */
a = md5I( b, c, d ) + X[K[2][i]];
break;
}
a = 0xFFFFFFFF & (ABCD[j] + a + T[round][i]);
ABCD[j] = b + (0xFFFFFFFF & ((a << s) | (a >> (32 - s))));
}
}
/* Use the stored original A, B, C, D values to perform
* one last convolution.
*/
for (i = 0; i < 4; i++)
ABCD[i] = 0xFFFFFFFF & (ABCD[i] + KeepABCD[i]);
} /* Permute */
/* -------------------------------------------------------------------------- **
* Functions:
*/
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx)
/* ------------------------------------------------------------------------ **
* Initialize an MD5 context.
*
* Input: ctx - A pointer to the MD5 context structure to be initialized.
* Contexts are typically created thusly:
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
*
* Output: A pointer to the initialized context (same as <ctx>).
*
* Notes: The purpose of the context is to make it possible to generate
* an MD5 Message Digest in stages, rather than having to pass a
* single large block to a single MD5 function. The context
* structure keeps track of various bits of state information.
*
* Once the context is initialized, the blocks of message data
* are passed to the <auth_md5SumCtx()> function. Once the
* final bit of data has been handed to <auth_md5SumCtx()> the
* context can be closed out by calling <auth_md5CloseCtx()>,
* which also calculates the final MD5 result.
*
* Don't forget to free an allocated context structure when
* you've finished using it.
*
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
ctx->len = 0;
ctx->b_used = 0;
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
/* 'round. The initial values are those */
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
/* provides these values as bytes, not as longwords, and the */
/* bytes are arranged in little-endian order as if they were */
/* the bytes of (little endian) 32-bit ints. That's */
/* confusing as all getout (to me, anyway). The values given */
/* here are provided as 32-bit values in C language format, */
/* so they are endian-agnostic. */
return (ctx);
} /* auth_md5InitCtx */
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len)
/* ------------------------------------------------------------------------ **
* Build an MD5 Message Digest within the given context.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* src - A chunk of source data. This will be used to drive
* the MD5 algorithm.
* len - The number of bytes in <src>.
*
* Output: A pointer to the updated context (same as <ctx>).
*
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
*
* ------------------------------------------------------------------------ **
*/
{
int i;
/* Add the new block's length to the total length.
*/
ctx->len += (uint32_t) len;
/* Copy the new block's data into the context block.
* Call the Permute() function whenever the context block is full.
*/
for (i = 0; i < len; i++)
{
ctx->block[ctx->b_used] = src[i];
(ctx->b_used)++;
if (64 == ctx->b_used)
{
Permute(ctx->ABCD, ctx->block);
ctx->b_used = 0;
}
}
/* Return the updated context.
*/
return (ctx);
} /* auth_md5SumCtx */
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst)
/* ------------------------------------------------------------------------ **
* Close an MD5 Message Digest context and generate the final MD5 sum.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* dst - A pointer to at least 16 bytes of memory, which will
* receive the finished MD5 sum.
*
* Output: A pointer to the closed context (same as <ctx>).
* You might use this to free a malloc'd context structure. :)
*
* Notes: The context (<ctx>) is returned in an undefined state.
* It must be re-initialized before re-use.
*
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
int i;
uint32_t l;
/* Add the required 0x80 padding initiator byte.
* The auth_md5SumCtx() function always permutes and resets the context
* block when it gets full, so we know that there must be at least one
* free byte in the context block.
*/
ctx->block[ctx->b_used] = 0x80;
(ctx->b_used)++;
/* Zero out any remaining free bytes in the context block.
*/
for (i = ctx->b_used; i < 64; i++)
ctx->block[i] = 0;
/* We need 8 bytes to store the length field.
* If we don't have 8, call Permute() and reset the context block.
*/
if (56 < ctx->b_used)
{
Permute(ctx->ABCD, ctx->block);
for (i = 0; i < 64; i++)
ctx->block[i] = 0;
}
/* Add the total length and perform the final perumation.
* Note: The 60'th byte is read from the *original* <ctx->len> value
* and shifted to the correct position. This neatly avoids
* any MAXINT numeric overflow issues.
*/
l = ctx->len << 3;
for (i = 0; i < 4; i++)
ctx->block[56 + i] |= GetLongByte( l, i );
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
Permute(ctx->ABCD, ctx->block);
/* Now copy the result into the output buffer and we're done.
*/
for (i = 0; i < 4; i++)
{
dst[0 + i] = GetLongByte( ctx->ABCD[0], i );
dst[4 + i] = GetLongByte( ctx->ABCD[1], i );
dst[8 + i] = GetLongByte( ctx->ABCD[2], i );
dst[12 + i] = GetLongByte( ctx->ABCD[3], i );
}
/* Return the context.
* This is done for compatibility with the other auth_md5*Ctx() functions.
*/
return (ctx);
} /* auth_md5CloseCtx */
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len)
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - Source data block to be MD5'd.
* len - The length, in bytes, of the source block.
* (Note that the length is given in bytes, not bits.)
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
auth_md5Ctx ctx[1];
(void) auth_md5InitCtx(ctx); /* Open a context. */
(void) auth_md5SumCtx(ctx, src, len); /* Pass only one block. */
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
return (dst); /* Makes life easy. */
} /* auth_md5Sum */
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - filepath of the file to be checked
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
auth_md5Ctx ctx[1];
FILE * file;
unsigned int blksize = 0;
unsigned int read = 0;
file = fopen(src, "rb");
if (file == NULL)
{
return NULL;
}
(void) auth_md5InitCtx(ctx); /* Open a context. */
fseek(file, 0, SEEK_END);
unsigned long long filesize = ftell(file);
rewind(file);
if (filesize < 1048576) //1MB cache for files bigger than 1 MB
blksize = filesize;
else blksize = 1048576;
unsigned char * buffer = malloc(blksize);
if (buffer == NULL)
{
//no memory
fclose(file);
return NULL;
}
do
{
read = fread(buffer, 1, blksize, file);
(void) auth_md5SumCtx(ctx, buffer, read); /* Pass only one block. */
} while (read > 0);
fclose(file);
free(buffer);
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
return (dst); /* Makes life easy. */
} /* auth_md5Sum */
const char * MD5ToString(const unsigned char * hash, char * dst)
{
char hexchar[3];
short i = 0, n = 0;
for (i = 0; i < 16; i++)
{
sprintf(hexchar, "%02X", hash[i]);
dst[n++] = hexchar[0];
dst[n++] = hexchar[1];
}
dst[n] = 0x00;
return dst;
}
unsigned char * StringToMD5(const char * hash, unsigned char * dst)
{
char hexchar[2];
short i = 0, n = 0;
for (i = 0; i < 16; i++)
{
hexchar[0] = hash[n++];
hexchar[1] = hash[n++];
dst[i] = STR2HEX( hexchar[0] );
dst[i] <<= 4;
dst[i] += STR2HEX( hexchar[1] );
}
return dst;
}
/* ========================================================================== */

241
source/utils/MD5.h Normal file
View File

@ -0,0 +1,241 @@
#ifndef MD5_H
#define MD5_H
#ifdef __cplusplus
extern "C"
{
#endif
/* ========================================================================== **
*
* MD5.h
*
* Copyright:
* Copyright (C) 2003-2005 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: MD5.h,v 0.6 2005/06/08 18:35:59 crh Exp $
*
* Modifications and additions by dimok
*
* -------------------------------------------------------------------------- **
*
* Description:
* Implements the MD5 hash algorithm, as described in RFC 1321.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* None of this will make any sense unless you're studying RFC 1321 as you
* read the code.
*
* MD5 is described in RFC 1321.
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
* MD5 is very similar to MD4, but not quite similar enough to justify
* putting the two into a single module. Besides, I wanted to add a few
* extra functions to this one to expand its usability.
*
* There are three primary motivations for this particular implementation.
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
* wanted to learn from the experience.
* 2) Portability. I wanted an implementation that I knew to be portable
* to a reasonable number of platforms. In particular, the algorithm is
* designed with little-endian platforms in mind, but I wanted an
* endian-agnostic implementation.
* 3) Compactness. While not an overriding goal, I thought it worth-while
* to see if I could reduce the overall size of the result. This is in
* keeping with my hopes that this library will be suitable for use in
* some embedded environments.
* Beyond that, cleanliness and clarity are always worth pursuing.
*
* As mentioned above, the code really only makes sense if you are familiar
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
* quirky, however, so you'll want to be reading carefully.
*
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
*
* -------------------------------------------------------------------------- **
*
* References:
* IETF RFC 1321: The MD5 Message-Digest Algorithm
* Ron Rivest. IETF, April, 1992
*
* ========================================================================== **
*/
/* -------------------------------------------------------------------------- **
* Typedefs:
*/
typedef struct
{
unsigned int len;
unsigned int ABCD[4];
int b_used;
unsigned char block[64];
} auth_md5Ctx;
/* -------------------------------------------------------------------------- **
* Functions:
*/
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx);
/* ------------------------------------------------------------------------ **
* Initialize an MD5 context.
*
* Input: ctx - A pointer to the MD5 context structure to be initialized.
* Contexts are typically created thusly:
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
*
* Output: A pointer to the initialized context (same as <ctx>).
*
* Notes: The purpose of the context is to make it possible to generate
* an MD5 Message Digest in stages, rather than having to pass a
* single large block to a single MD5 function. The context
* structure keeps track of various bits of state information.
*
* Once the context is initialized, the blocks of message data
* are passed to the <auth_md5SumCtx()> function. Once the
* final bit of data has been handed to <auth_md5SumCtx()> the
* context can be closed out by calling <auth_md5CloseCtx()>,
* which also calculates the final MD5 result.
*
* Don't forget to free an allocated context structure when
* you've finished using it.
*
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
*
* ------------------------------------------------------------------------ **
*/
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len);
/* ------------------------------------------------------------------------ **
* Build an MD5 Message Digest within the given context.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* src - A chunk of source data. This will be used to drive
* the MD5 algorithm.
* len - The number of bytes in <src>.
*
* Output: A pointer to the updated context (same as <ctx>).
*
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
*
* ------------------------------------------------------------------------ **
*/
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst);
/* ------------------------------------------------------------------------ **
* Close an MD5 Message Digest context and generate the final MD5 sum.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* dst - A pointer to at least 16 bytes of memory, which will
* receive the finished MD5 sum.
*
* Output: A pointer to the closed context (same as <ctx>).
* You might use this to free a malloc'd context structure. :)
*
* Notes: The context (<ctx>) is returned in an undefined state.
* It must be re-initialized before re-use.
*
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
*
* ------------------------------------------------------------------------ **
*/
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len);
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - Source data block to be MD5'd.
* len - The length, in bytes, of the source block.
* (Note that the length is given in bytes, not bits.)
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - filepath to the file to be MD5'd.
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
const char * MD5ToString(const unsigned char *hash, char *dst);
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
/* ========================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* AUTH_MD5_H */

View File

@ -2,5 +2,7 @@
#define TOOLS_H_ #define TOOLS_H_
#define cut_bounds(x, min, max) ( ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x) ) #define cut_bounds(x, min, max) ( ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x) )
#define ALIGN(x) (((x) + 3) & ~3)
#define ALIGN32(x) (((x) + 31) & ~31)
#endif #endif

View File

@ -1,4 +1,5 @@
#include "nandtitle.h" #include "nandtitle.h"
#include "usbloader/playlog.h"
#include "gecko.h" #include "gecko.h"
NandTitle NandTitles; NandTitle NandTitles;
@ -93,6 +94,8 @@ s32 NandTitle::Get()
} }
ISFS_Deinitialize(); ISFS_Deinitialize();
//If not started from SystemMenu, create playlog while we got nand access.
Playlog_Create();
MagicPatches(0); MagicPatches(0);
return 1; return 1;
} }