From 6850d680745b2146da4e35e53a900ac2845fb81c Mon Sep 17 00:00:00 2001 From: dimok321 <15055714+dimok789@users.noreply.github.com> Date: Mon, 27 Dec 2010 09:44:27 +0000 Subject: [PATCH] *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. --- gui.pnproj | 2 +- source/GameBootProcess.cpp | 6 + source/banner/OpeningBNR.cpp | 159 +++++++ source/banner/OpeningBNR.hpp | 46 ++ source/banner/openingbnr.c | 562 ------------------------- source/banner/openingbnr.h | 47 --- source/libs/libntfs/libcustomntfs.a | Bin 582894 -> 583042 bytes source/prompts/GameWindow.cpp | 4 +- source/prompts/PromptWindows.cpp | 1 - source/settings/CSettings.cpp | 7 + source/settings/CSettings.h | 1 + source/settings/menus/GameLoadSM.cpp | 10 + source/sys.cpp | 4 + source/usbloader/playlog.c | 163 +++++++ source/usbloader/playlog.h | 18 + source/utils/MD5.c | 608 +++++++++++++++++++++++++++ source/utils/MD5.h | 241 +++++++++++ source/utils/tools.h | 2 + source/wad/nandtitle.cpp | 3 + 19 files changed, 1271 insertions(+), 613 deletions(-) create mode 100644 source/banner/OpeningBNR.cpp create mode 100644 source/banner/OpeningBNR.hpp delete mode 100644 source/banner/openingbnr.c delete mode 100644 source/banner/openingbnr.h create mode 100644 source/usbloader/playlog.c create mode 100644 source/usbloader/playlog.h create mode 100644 source/utils/MD5.c create mode 100644 source/utils/MD5.h diff --git a/gui.pnproj b/gui.pnproj index 55da86f4..d6cd31ef 100644 --- a/gui.pnproj +++ b/gui.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/GameBootProcess.cpp b/source/GameBootProcess.cpp index 8eb8c207..1fd13964 100644 --- a/source/GameBootProcess.cpp +++ b/source/GameBootProcess.cpp @@ -10,11 +10,13 @@ #include "settings/CGameSettings.h" #include "usbloader/frag.h" #include "usbloader/wbfs.h" +#include "usbloader/playlog.h" #include "settings/newtitles.h" #include "patches/fst.h" #include "patches/gamepatches.h" #include "patches/wip.h" #include "system/IosLoader.h" +#include "banner/OpeningBNR.hpp" #include "wad/nandtitle.h" #include "menu/menus.h" #include "memory/memory.h" @@ -211,6 +213,10 @@ int BootGame(const char * gameID) UnmountEXT(); SDCard_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); diff --git a/source/banner/OpeningBNR.cpp b/source/banner/OpeningBNR.cpp new file mode 100644 index 00000000..f9eefb62 --- /dev/null +++ b/source/banner/OpeningBNR.cpp @@ -0,0 +1,159 @@ +#include +#include +#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; +} diff --git a/source/banner/OpeningBNR.hpp b/source/banner/OpeningBNR.hpp new file mode 100644 index 00000000..2ec69a22 --- /dev/null +++ b/source/banner/OpeningBNR.hpp @@ -0,0 +1,46 @@ +#ifndef OPENING_BNR_HPP_ +#define OPENING_BNR_HPP_ + +#include + +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 diff --git a/source/banner/openingbnr.c b/source/banner/openingbnr.c deleted file mode 100644 index b1ab8aca..00000000 --- a/source/banner/openingbnr.c +++ /dev/null @@ -1,562 +0,0 @@ -/**************************************************************************** - * USB Loader GX Team - * openingbnr - * - * Extract opening.bnr/banner.bin/sound.bin/icon.bin - * - * Copyright 2008 Magicus - * 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 -#include -#include -#include - -#include -#include -#include -#include - -#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 diff --git a/source/banner/openingbnr.h b/source/banner/openingbnr.h deleted file mode 100644 index dd36354c..00000000 --- a/source/banner/openingbnr.h +++ /dev/null @@ -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 diff --git a/source/libs/libntfs/libcustomntfs.a b/source/libs/libntfs/libcustomntfs.a index 5bba67a53d4241450b10ed06088cc2a13ea1a4e2..a141dce6d50b62b2fe5780d1f60caaa582a178b8 100644 GIT binary patch delta 7967 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 delta 7702 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 JjiI_t{|$&%P51x+ diff --git a/source/prompts/GameWindow.cpp b/source/prompts/GameWindow.cpp index 6fb3e92c..426d6e47 100644 --- a/source/prompts/GameWindow.cpp +++ b/source/prompts/GameWindow.cpp @@ -12,7 +12,7 @@ #include "prompts/PromptWindows.h" #include "language/gettext.h" #include "menu/menus.h" -#include "bannersound.h" +#include "banner/OpeningBNR.hpp" #define NONE 0 #define LEFT 1 @@ -272,7 +272,7 @@ void GameWindow::LoadGameSound(const u8 * id) } u32 gameSoundDataLen; - const u8 *gameSoundData = LoadBannerSound(id, &gameSoundDataLen); + const u8 *gameSoundData = BNRInstance::Instance()->GetBannerSound(id, &gameSoundDataLen); if (gameSoundData) { gameSound = new GuiSound(gameSoundData, gameSoundDataLen, Settings.gamesoundvolume, true); diff --git a/source/prompts/PromptWindows.cpp b/source/prompts/PromptWindows.cpp index 0bafeff4..a24c11b2 100644 --- a/source/prompts/PromptWindows.cpp +++ b/source/prompts/PromptWindows.cpp @@ -42,7 +42,6 @@ #include "language/UpdateLanguage.h" #include "gecko.h" #include "lstub.h" -#include "bannersound.h" #include "buildtype.h" /*** Extern variables ***/ diff --git a/source/settings/CSettings.cpp b/source/settings/CSettings.cpp index 0870de5b..ec1b86b0 100644 --- a/source/settings/CSettings.cpp +++ b/source/settings/CSettings.cpp @@ -105,6 +105,7 @@ void CSettings::SetDefault() FatInstallToDir = 0; InstallPartitions = ONLY_GAME_PARTITION; beta_upgrades = 0; + PlaylogUpdate = 1; widescreen = (CONF_GetAspectRatio() == CONF_ASPECT_16_9); Theme::SetDefault(); //! We need to move this later @@ -213,6 +214,7 @@ bool CSettings::Save() fprintf(file, "FatInstallToDir = %d\n ", FatInstallToDir); fprintf(file, "InstallPartitions = %08X\n ", InstallPartitions); fprintf(file, "beta_upgrades = %d\n ", beta_upgrades); + fprintf(file, "PlaylogUpdate = %d\n ", PlaylogUpdate); fprintf(file, "returnTo = %s\n ", returnTo); fclose(file); @@ -441,6 +443,11 @@ bool CSettings::SetSetting(char *name, char *value) if (sscanf(value, "%d", &i) == 1) beta_upgrades = i; return true; } + else if (strcmp(name, "PlaylogUpdate") == 0) + { + if (sscanf(value, "%d", &i) == 1) PlaylogUpdate = i; + return true; + } else if (strcmp(name, "InstallPartitions") == 0) { InstallPartitions = strtoul(value, 0, 16); diff --git a/source/settings/CSettings.h b/source/settings/CSettings.h index 2031ebf4..1b9497de 100644 --- a/source/settings/CSettings.h +++ b/source/settings/CSettings.h @@ -108,6 +108,7 @@ class CSettings short FatInstallToDir; u32 InstallPartitions; short beta_upgrades; + short PlaylogUpdate; char returnTo[20]; protected: bool SetSetting(char *name, char *value); diff --git a/source/settings/menus/GameLoadSM.cpp b/source/settings/menus/GameLoadSM.cpp index cd39c4f7..b14f348d 100644 --- a/source/settings/menus/GameLoadSM.cpp +++ b/source/settings/menus/GameLoadSM.cpp @@ -115,6 +115,7 @@ GameLoadSM::GameLoadSM() Options->SetName(Idx++, "%s", tr( "Error 002 fix" )); Options->SetName(Idx++, "%s", tr( "Install partitions" )); Options->SetName(Idx++, "%s", tr( "Return To" )); + Options->SetName(Idx++, "%s", tr( "Messageboard Update" )); SetOptionValues(); @@ -195,6 +196,9 @@ void GameLoadSM::SetOptionValues() TitleName = NandTitles.NameFromIndex(haveTitle); TitleName = TitleName ? TitleName : strlen(Settings.returnTo) > 0 ? Settings.returnTo : tr(OnOffText[0]); Options->SetValue(Idx++, "%s", TitleName); + + //! Settings: Messageboard Update + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.PlaylogUpdate] )); } int GameLoadSM::GetMenuInternal() @@ -320,6 +324,12 @@ int GameLoadSM::GetMenuInternal() 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(); return MENU_NONE; diff --git a/source/sys.cpp b/source/sys.cpp index 98a13ca5..1006054c 100644 --- a/source/sys.cpp +++ b/source/sys.cpp @@ -8,6 +8,7 @@ #include "language/gettext.h" #include "network/networkops.h" #include "utils/ResourceManager.h" +#include "usbloader/playlog.h" #include "FontSystem.h" #include "audio.h" #include "fatmounter.h" @@ -97,6 +98,9 @@ void ExitApp(void) UnmountEXT(); SDCard_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) diff --git a/source/usbloader/playlog.c b/source/usbloader/playlog.c new file mode 100644 index 00000000..35c78fa9 --- /dev/null +++ b/source/usbloader/playlog.c @@ -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 +#include +#include +#include +#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; +} diff --git a/source/usbloader/playlog.h b/source/usbloader/playlog.h new file mode 100644 index 00000000..7a13f64b --- /dev/null +++ b/source/usbloader/playlog.h @@ -0,0 +1,18 @@ +#ifndef PLAYLOG_H_ +#define PLAYLOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int Playlog_Create(void); +int Playlog_Update(const char * ID, const u16 * title); +int Playlog_Delete(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/MD5.c b/source/utils/MD5.c new file mode 100644 index 00000000..c672db10 --- /dev/null +++ b/source/utils/MD5.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 + * 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 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; /* handles the rotation of ABCD. */ + s = S[round][i % 4]; /* 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 ). + * + * 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 function. Once the + * final bit of data has been handed to the + * context can be closed out by calling , + * which also calculates the final MD5 result. + * + * Don't forget to free an allocated context structure when + * you've finished using it. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ +{ + 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 . + * + * Output: A pointer to the updated context (same as ). + * + * See Also: , , + * + * ------------------------------------------------------------------------ ** + */ +{ + 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 ). + * You might use this to free a malloc'd context structure. :) + * + * Notes: The context () is returned in an undefined state. + * It must be re-initialized before re-use. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ +{ + 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* 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 , 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 . + * + * This function is interface-compatible with the + * 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_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 , 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 . + * + * This function is interface-compatible with the + * 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_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; +} + +/* ========================================================================== */ diff --git a/source/utils/MD5.h b/source/utils/MD5.h new file mode 100644 index 00000000..07902c2b --- /dev/null +++ b/source/utils/MD5.h @@ -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 ). + * + * 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 function. Once the + * final bit of data has been handed to the + * context can be closed out by calling , + * 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_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 . + * + * Output: A pointer to the updated context (same as ). + * + * See Also: , , + * + * ------------------------------------------------------------------------ ** + */ + + 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 ). + * You might use this to free a malloc'd context structure. :) + * + * Notes: The context () is returned in an undefined state. + * It must be re-initialized before re-use. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ + + 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 , 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 . + * + * This function is interface-compatible with the + * 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: + * + * ------------------------------------------------------------------------ ** + */ + + 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 , 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 . + * + * This function is interface-compatible with the + * 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: + * + * ------------------------------------------------------------------------ ** + */ + + 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 */ diff --git a/source/utils/tools.h b/source/utils/tools.h index 91c7cb37..ec72dafc 100644 --- a/source/utils/tools.h +++ b/source/utils/tools.h @@ -2,5 +2,7 @@ #define TOOLS_H_ #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 diff --git a/source/wad/nandtitle.cpp b/source/wad/nandtitle.cpp index 9963fbfd..116c9ee1 100644 --- a/source/wad/nandtitle.cpp +++ b/source/wad/nandtitle.cpp @@ -1,4 +1,5 @@ #include "nandtitle.h" +#include "usbloader/playlog.h" #include "gecko.h" NandTitle NandTitles; @@ -93,6 +94,8 @@ s32 NandTitle::Get() } ISFS_Deinitialize(); + //If not started from SystemMenu, create playlog while we got nand access. + Playlog_Create(); MagicPatches(0); return 1; }