Q=wtDTEC|0nnXxio^zhQ0hTL>q`30j3)sKPrju`!=ui=LLTDRzT!~*v>yU%XRy@MQ1
qK?J{9zESBAg^`-oaTgD|vJw0!H*G}p=QaFf*27AU?5hfuZ~Sk+esN*|
delta 7702
zcmcgx3v^Z0nf~`V_wHP5hyiZ%keGxdhKQK=Q$iXfh(dTjM95P}d__VrYFdMdz$nXB
zj1#6m&H}`dGT6ozg>vbtMQSap4=SQSGb2LmSc^&{w07zmT{7Rk=j?Mfcdc2SPS={V
z?z#K>|NZ}a|F5(6KKHKwRrbg)vis9yNm*4zW$BAqPusmqN#6c9-Wy*c`Pc4eze94*
zq`!Xm{%?e|%*7g#|MjYO$7McBfAf9cO%!L`y(aPhi9-`}33sph`up#OuT$v%bdT~B
z2VT5q&Avjpd+fmPQ)UdDN*NPa)YaO>Pi>c1@0*kQXBjP;@>1UUd?0yWb0#m2GAc@V
zcxEtVL-_tk_?2pULD%(Rh19uEVKtraC^&{(&P?QLLs)iu_BReX!q=sfxgy
zBW`z*@*TDf*$-Y9?XD<`9JT}h{%waSjUZO-cSq;1;Ijx*Bs(08l;~b4Z@$*mQ&S^G
zUkyH*>dHTE?liU2?Iez$C&!3?
z<@9-SV(>?BRUaFxsgZNJ59s_by&d-LRDmN?Jl3*{Z+
z!GWf`G8Ql-qgP_|TYTH00$ausfh7()bd&%Tuf)*5jG>Qn!YDiG3i~za<0JmS37^^-
z6T+8^S-CNE<-pv#lV<5ztR*qscgN5@G4vA-ZM9&^BqHmddE_0L+^ammWyLsQxlULI
zA)bQ%V~)Bv{o670xfuG-m(#Y0p+`G3xBMxX%0=q~Dg5I>J2as-Mr=+Dy@HPn+8GNT
zjA1_(Lw_rV-W@~#Acj5?saYcL6OjW;Wv3O%xlQJX)Ql@!q1TA=HU0#cTbIk^)&iF$
z@RSs4yo^Yzi56c?3=$P-nZrcs8V?c0X*}%9)15>m{FCLfd334UZNZo_zJ7(ABFgwK
zG^5Mio&XFe=NDB^CI4ZCOkSdO1QO@rVxlUEL2!v1fCDaWAi6=Du#0Gl#)pZjH9kQ!
zm2Yd1_h5#fHQ;Hk;SU;QLF!jr0UIW0pKQdSmWvvr!rL2VGM`=+3e8dZ_iUMD*rM#x
zw$vN8Y%y%vYuJKpOyyBc(c$lJirVsYlW9wuVasG?%ezf-k+_k|n&p$J#o8s9GhJgm
zd6oQ5vrP7)Eiii-ixychy3UoN`9wGJ)D}!!%+I$V0iJ$`(!bbZ>YrBnUv8BJy;|Qw
zaCM9*M0AsWBI1c=YK({RW{qLhEgB<{vowZ(vo+2ns@FJ&C>mvWMtMYY9eytnf-p}D
z6%x(YxRhvt#??d%HLfLEq;Vb5VvUjHB^uWgE!7x-xmDxEM9ZRhbyxd+tL|ExKen?V
zGkO&jSCy!JwxUAq;B}F$x68544qj0n*}GBx(K&RYJGy1Q@~m9xoG2=)qMSfwd1OFF0@9?@l%IyhRy9XYj#GanwV@NP1{bZYM%;IUGE3>?kXhV*&f7ZQsNC$w(;QeGJE>N^YgcU3H3skj@~+)
zcth`JpLMURq5MjuX6q>Am?$)*g{Tj9^{#xo`w`gH6S8-2fQ=jA%euZtGI{3&JDgM5
zOKO3EbwvFSqndYIYEd*sitmSovoBrR8@c^EvQ9+Ozb~i6MYexecH5EL4#;1o@Xnj1
z~YjtDVdTRFlbPRMW?YW`&aZ>bD>;ne*S0xk2j!_EJ7RXodM+
zuzOKJ0ymZ5Ms*V+PpEkM1h*;_cS({cM$rITUrJ70ALG^-aLOip_2X9KVQbRk3ALXX
zslcu02^AN$viSaCh@1gjZ3tu7xU^9GI`9D7@3zj
zeVvuWT^Dh}saDfm;8#z`tl$-J!R86;ta1GL37IIT_F?Qw9(xjfqX&U`%tbrQb56=D
zt(t?}bW%Rx2tyM7T&DdoIQNt
zH^^oVpHbw^-7JSd)^omU8aaBL>KMX+ef%(3!7Z43y>px@Y{7AA7zV<593i8}sq$KQ
zwbnUKCH$MLuuxn#y^WzB<1=5elH0nFH?^ofgFAYuy1=D3>BZ<*C2}Cj#h2Uvx=XJ?
ze**A3G5sGov|We(L{9I)-jKlQr)7q?n)A_c<7pYUTr{8?A2IE6b+I6ZUKT?)$I$IA
zy$yqfFi${EO6G2Ug9YF)6ieYtN$~QQ8d?K>yTMZ4sBOM3~QLx5!1hc4?(Tg
zPOJ?2=tGYh{9OkBsDVH6u|R!kUA2^ZxWm9(JiMI5%N{}EJs(@~28JJcAPfF^c%y*_
z4SWKapZcB5PA$=4LFJTbT(8c+zy2LwXeu?KRraT0?ggPR5$wVd$!f`4{iYMWbtV
zH+-GO*Zy8ETH>*WaQtw))q8+-G(!@DqAyM&tR#30tLMF0*e6Zr&rYAOz%FK0>PXKIdzFUarWcZvB7ZdE%kN*ds`s^Rbm^;7S9x7Y1LZaf+X4Re4%hoj~<8qFcRaj`dUElGfrkx@f%Q6Mh5RK$Wk4@0
z7W~z9YUTO5YJ>8YP&~=1uJL+;YojW$TRuXGdDXbp{|$r8bra6(GNB_zxxMG}MZAGa
z4UGAzGw^vI+hJf{a9(ELqRY*OjXLf&
z{L}HZ5BtfrPx#5TjpPObD!D&CkF7|n1@81y5m@7=BGBiTVW8i@uzH4D7=c}eJgnCB
z7sNCk&NOhfhkGg5f!)X*D2PGzb`spOEZ@yl^fv*=*LR1P_jF|Pd(Wtk_jk-cWbb9F}ga3xX|J27K)4-Ts
z>;4Z*8tUz^A#~2ifA^B+1`u!UsJBrc%j_br-e9ASojvI1!`^Sy+fh|ljUVGDrCZ&R
z0tmBLW2^ks1v-p+>oV%6$B;+8>E$7SM_Vrsfjvg;VS29)U-o2BS8%~Az7zwO8hE~e
z@AUl(!U*l_Wi<)E_5K;eWL~YpZ%=+$;cU#VE=;C7RQ+g!qN_B&Z~?WX*L529_XM>M
zczZ&k9}smK(E$;YJ!eT&<0maQ;A%_M0TBqe9$)Ph+FsG;nUzjro3ZJjaJ9Yah&+|=
zy(p7Ymn(zR6~ddI!ibf6{awM^Rd<8#Mwp}B$ftVaYvf;Fl&Q|2I#tepS@s|09iyV0
z%AyGVx;k`C^pB!Se&+c=N@VtgxaSr+z3%^GU+Rkc={{H9`O)p8iJ^)zhlBsw)E`?l
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;
}