undo the code formatting. somehow it got screwed up
@ -2,8 +2,8 @@
|
||||
<app version="1">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r908</version>
|
||||
<release_date>201002090353</release_date>
|
||||
<version>1.0 r909</version>
|
||||
<release_date>201002091053</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
@ -65,9 +65,10 @@ typedef struct ftgxDataOffset_ {
|
||||
* @param vertexIndex Optional vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. If not specified default value is GX_VTXFMT1.
|
||||
*/
|
||||
FreeTypeGX::FreeTypeGX(uint8_t textureFormat, uint8_t vertexIndex, uint32_t compatibilityMode)
|
||||
:
|
||||
ftFace(NULL),
|
||||
ftFace_fromFile(NULL) {
|
||||
:
|
||||
ftFace(NULL),
|
||||
ftFace_fromFile(NULL)
|
||||
{
|
||||
FT_Init_FreeType(&this->ftLibrary);
|
||||
|
||||
this->textureFormat = textureFormat;
|
||||
@ -94,8 +95,8 @@ FreeTypeGX::~FreeTypeGX() {
|
||||
*/
|
||||
wchar_t* FreeTypeGX::charToWideChar(const char* strChar) {
|
||||
wchar_t *strWChar;
|
||||
strWChar = new(std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||
if (!strWChar) return NULL;
|
||||
strWChar = new(std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||
if(!strWChar) return NULL;
|
||||
// UTF-8
|
||||
int bt;
|
||||
bt = mbstowcs(strWChar, strChar, strlen(strChar));
|
||||
@ -260,29 +261,32 @@ void FreeTypeGX::clearGlyphData() {
|
||||
GX_DrawDone();
|
||||
GX_Flush();
|
||||
|
||||
for ( std::map<uint16_t, FTGX_Cache>::iterator i = this->fontDatas.begin(); i != this->fontDatas.end(); i++) {
|
||||
for ( FTGX_Cache::iterator j = i->second.begin(); j != i->second.end(); j++) {
|
||||
free(j->second.glyphDataTexture);
|
||||
}
|
||||
i->second.clear();
|
||||
for ( std::map<uint16_t, FTGX_Cache>::iterator i = this->fontDatas.begin(); i != this->fontDatas.end(); i++)
|
||||
{
|
||||
for ( FTGX_Cache::iterator j = i->second.begin(); j != i->second.end(); j++)
|
||||
{
|
||||
free(j->second.glyphDataTexture);
|
||||
}
|
||||
i->second.clear();
|
||||
}
|
||||
/* for ( std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) {
|
||||
free(i->second.glyphDataTexture);
|
||||
}
|
||||
*/
|
||||
/* for ( std::map<wchar_t, ftgxCharData>::iterator i = this->fontData.begin(); i != this->fontData.end(); i++) {
|
||||
free(i->second.glyphDataTexture);
|
||||
}
|
||||
*/
|
||||
this->fontDatas.clear();
|
||||
}
|
||||
|
||||
void FreeTypeGX::changeSize(FT_UInt vPointSize, FT_UInt hPointSize/*=0*/) {
|
||||
if (hPointSize == 0) hPointSize = vPointSize;
|
||||
if (vPointSize > 255) vPointSize = 255;// limit to 255
|
||||
if (hPointSize > 255) hPointSize = 255;
|
||||
if (this->ftPointSize_v != vPointSize || this->ftPointSize_h != hPointSize) {
|
||||
if(hPointSize == 0) hPointSize = vPointSize;
|
||||
if(vPointSize > 255) vPointSize = 255;// limit to 255
|
||||
if(hPointSize > 255) hPointSize = 255;
|
||||
if(this->ftPointSize_v != vPointSize || this->ftPointSize_h != hPointSize)
|
||||
{
|
||||
// this->clearGlyphData();
|
||||
this->ftPointSize_v = vPointSize;
|
||||
this->ftPointSize_h = hPointSize;
|
||||
FT_Set_Pixel_Sizes(this->ftFace, this->ftPointSize_h, this->ftPointSize_v);
|
||||
}
|
||||
this->ftPointSize_v = vPointSize;
|
||||
this->ftPointSize_h = hPointSize;
|
||||
FT_Set_Pixel_Sizes(this->ftFace, this->ftPointSize_h, this->ftPointSize_v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,42 +360,44 @@ uint16_t FreeTypeGX::adjustTextureHeight(uint16_t textureHeight, uint8_t texture
|
||||
* @param charCode The requested glyph's character code.
|
||||
* @return A pointer to the allocated font structure.
|
||||
*/
|
||||
ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode) {
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
return cacheGlyphData(charCode, fontData);
|
||||
ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode)
|
||||
{
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
return cacheGlyphData(charCode, fontData);
|
||||
}
|
||||
ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData) {
|
||||
FT_UInt gIndex;
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData)
|
||||
{
|
||||
FT_UInt gIndex;
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
|
||||
gIndex = FT_Get_Char_Index( this->ftFace, charCode );
|
||||
if (!FT_Load_Glyph(this->ftFace, gIndex, FT_LOAD_DEFAULT )) {
|
||||
FT_Render_Glyph( this->ftSlot, FT_RENDER_MODE_NORMAL );
|
||||
gIndex = FT_Get_Char_Index( this->ftFace, charCode );
|
||||
if (!FT_Load_Glyph(this->ftFace, gIndex, FT_LOAD_DEFAULT )) {
|
||||
FT_Render_Glyph( this->ftSlot, FT_RENDER_MODE_NORMAL );
|
||||
|
||||
if (this->ftSlot->format == FT_GLYPH_FORMAT_BITMAP) {
|
||||
FT_Bitmap *glyphBitmap = &this->ftSlot->bitmap;
|
||||
if (this->ftSlot->format == FT_GLYPH_FORMAT_BITMAP) {
|
||||
FT_Bitmap *glyphBitmap = &this->ftSlot->bitmap;
|
||||
|
||||
textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat);
|
||||
textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat);
|
||||
textureWidth = adjustTextureWidth(glyphBitmap->width, this->textureFormat);
|
||||
textureHeight = adjustTextureHeight(glyphBitmap->rows, this->textureFormat);
|
||||
|
||||
fontData[charCode] = (ftgxCharData) {
|
||||
this->ftSlot->bitmap_left,
|
||||
this->ftSlot->advance.x >> 6,
|
||||
gIndex,
|
||||
textureWidth,
|
||||
textureHeight,
|
||||
this->ftSlot->bitmap_top,
|
||||
this->ftSlot->bitmap_top,
|
||||
glyphBitmap->rows - this->ftSlot->bitmap_top,
|
||||
NULL
|
||||
};
|
||||
this->loadGlyphData(glyphBitmap, &fontData[charCode]);
|
||||
fontData[charCode] = (ftgxCharData) {
|
||||
this->ftSlot->bitmap_left,
|
||||
this->ftSlot->advance.x >> 6,
|
||||
gIndex,
|
||||
textureWidth,
|
||||
textureHeight,
|
||||
this->ftSlot->bitmap_top,
|
||||
this->ftSlot->bitmap_top,
|
||||
glyphBitmap->rows - this->ftSlot->bitmap_top,
|
||||
NULL
|
||||
};
|
||||
this->loadGlyphData(glyphBitmap, &fontData[charCode]);
|
||||
|
||||
return &fontData[charCode];
|
||||
}
|
||||
}
|
||||
return &fontData[charCode];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -546,8 +552,8 @@ uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, const wchar_t *text, GXColor
|
||||
GXTexObj glyphTexture;
|
||||
FT_Vector pairDelta;
|
||||
ftgxDataOffset offset;
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
|
||||
if (textStyle & FTGX_JUSTIFY_MASK) {
|
||||
x_offset = this->getStyleOffsetWidth(this->getWidth(text), textStyle);
|
||||
}
|
||||
@ -643,7 +649,7 @@ uint16_t FreeTypeGX::getWidth(const wchar_t *text) {
|
||||
uint16_t strLength = wcslen(text);
|
||||
uint16_t strWidth = 0;
|
||||
FT_Vector pairDelta;
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
|
||||
for (uint16_t i = 0; i < strLength; i++) {
|
||||
|
||||
@ -697,8 +703,8 @@ uint16_t FreeTypeGX::getHeight(const wchar_t *text) {
|
||||
ftgxDataOffset* FreeTypeGX::getOffset(const wchar_t *text, ftgxDataOffset* offset) {
|
||||
uint16_t strLength = wcslen(text);
|
||||
int16_t strMax = 0, strMin = 9999;
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
|
||||
FTGX_Cache &fontData = this->fontDatas[ftPointSize_v | ftPointSize_h << 8];
|
||||
|
||||
for (uint16_t i = 0; i < strLength; i++) {
|
||||
|
||||
ftgxCharData* glyphData = NULL;
|
||||
|
@ -203,7 +203,9 @@ typedef struct ftgxDataOffset_ ftgxDataOffset;
|
||||
#define FTGX_COMPATIBILITY_GRRLIB FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_PASSCLR | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_NONE
|
||||
#define FTGX_COMPATIBILITY_LIBWIISPRITE FTGX_COMPATIBILITY_DEFAULT_TEVOP_GX_MODULATE | FTGX_COMPATIBILITY_DEFAULT_VTXDESC_GX_DIRECT
|
||||
|
||||
const GXColor ftgxWhite = (GXColor) {0xff, 0xff, 0xff, 0xff}
|
||||
const GXColor ftgxWhite = (GXColor) {
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
}
|
||||
; /**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
|
||||
/*! \class FreeTypeGX
|
||||
@ -231,7 +233,7 @@ private:
|
||||
uint8_t vertexIndex; /**< Vertex format descriptor index. */
|
||||
uint32_t compatibilityMode; /**< Compatibility mode for default tev operations and vertex descriptors. */
|
||||
// FTGX_Cache fontData; /**< Map which holds the glyph data structures for the corresponding characters. */
|
||||
std::map<uint16_t, FTGX_Cache> fontDatas;
|
||||
std::map<uint16_t, FTGX_Cache> fontDatas;
|
||||
|
||||
static uint16_t adjustTextureWidth(uint16_t textureWidth, uint8_t textureFormat);
|
||||
static uint16_t adjustTextureHeight(uint16_t textureHeight, uint8_t textureFormat);
|
||||
@ -242,7 +244,7 @@ private:
|
||||
void unloadFont();
|
||||
void clearGlyphData();
|
||||
ftgxCharData *cacheGlyphData(wchar_t charCode);
|
||||
ftgxCharData *cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData);
|
||||
ftgxCharData *cacheGlyphData(wchar_t charCode, FTGX_Cache &fontData);
|
||||
uint16_t cacheGlyphDataComplete();
|
||||
void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData);
|
||||
|
||||
|
@ -39,22 +39,26 @@
|
||||
#include "ZipFile.h"
|
||||
#include "language/gettext.h"
|
||||
|
||||
ZipFile::ZipFile(const char *filepath) {
|
||||
ZipFile::ZipFile(const char *filepath)
|
||||
{
|
||||
File = unzOpen(filepath);
|
||||
if (File)
|
||||
if(File)
|
||||
this->LoadList();
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile() {
|
||||
ZipFile::~ZipFile()
|
||||
{
|
||||
unzClose(File);
|
||||
}
|
||||
|
||||
bool ZipFile::LoadList() {
|
||||
bool ZipFile::LoadList()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipFile::ExtractAll(const char *dest) {
|
||||
if (!File)
|
||||
bool ZipFile::ExtractAll(const char *dest)
|
||||
{
|
||||
if(!File)
|
||||
return false;
|
||||
|
||||
bool Stop = false;
|
||||
@ -62,7 +66,7 @@ bool ZipFile::ExtractAll(const char *dest) {
|
||||
u32 blocksize = 1024*50;
|
||||
u8 *buffer = new u8[blocksize];
|
||||
|
||||
if (!buffer)
|
||||
if(!buffer)
|
||||
return false;
|
||||
|
||||
char writepath[MAXPATHLEN];
|
||||
@ -70,14 +74,16 @@ bool ZipFile::ExtractAll(const char *dest) {
|
||||
memset(filename, 0, sizeof(filename));
|
||||
|
||||
int ret = unzGoToFirstFile(File);
|
||||
if (ret != UNZ_OK)
|
||||
if(ret != UNZ_OK)
|
||||
Stop = true;
|
||||
|
||||
while (!Stop) {
|
||||
if (unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, NULL, NULL, NULL) != UNZ_OK)
|
||||
while(!Stop)
|
||||
{
|
||||
if(unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, NULL, NULL, NULL) != UNZ_OK)
|
||||
Stop = true;
|
||||
|
||||
if (!Stop && filename[strlen(filename)-1] != '/') {
|
||||
if(!Stop && filename[strlen(filename)-1] != '/')
|
||||
{
|
||||
u32 uncompressed_size = cur_file_info.uncompressed_size;
|
||||
|
||||
u32 done = 0;
|
||||
@ -95,31 +101,33 @@ bool ZipFile::ExtractAll(const char *dest) {
|
||||
|
||||
subfoldercreate(temppath);
|
||||
|
||||
if (ret == UNZ_OK) {
|
||||
if(ret == UNZ_OK)
|
||||
{
|
||||
FILE *pfile = fopen(writepath, "wb");
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
ShowProgress(tr("Extracting files..."), 0, pointer+1, done, uncompressed_size);
|
||||
|
||||
if (uncompressed_size - done < blocksize)
|
||||
if(uncompressed_size - done < blocksize)
|
||||
blocksize = uncompressed_size - done;
|
||||
|
||||
ret = unzReadCurrentFile(File, buffer, blocksize);
|
||||
|
||||
if (ret == 0)
|
||||
if(ret == 0)
|
||||
break;
|
||||
|
||||
fwrite(buffer, 1, blocksize, pfile);
|
||||
|
||||
done += ret;
|
||||
|
||||
} while (done < uncompressed_size);
|
||||
} while(done < uncompressed_size);
|
||||
|
||||
fclose(pfile);
|
||||
unzCloseCurrentFile(File);
|
||||
}
|
||||
}
|
||||
if (unzGoToNextFile(File) != UNZ_OK)
|
||||
if(unzGoToNextFile(File) != UNZ_OK)
|
||||
Stop = true;
|
||||
}
|
||||
|
||||
|
@ -30,27 +30,29 @@
|
||||
|
||||
#include "unzip/unzip.h"
|
||||
|
||||
typedef struct {
|
||||
u64 offset; // ZipFile offset
|
||||
u64 length; // uncompressed file length in 64 bytes for sizes higher than 4GB
|
||||
bool isdir; // 0 - file, 1 - directory
|
||||
char filename[256]; // full filename
|
||||
typedef struct
|
||||
{
|
||||
u64 offset; // ZipFile offset
|
||||
u64 length; // uncompressed file length in 64 bytes for sizes higher than 4GB
|
||||
bool isdir; // 0 - file, 1 - directory
|
||||
char filename[256]; // full filename
|
||||
} FileStructure;
|
||||
|
||||
class ZipFile {
|
||||
public:
|
||||
//!Constructor
|
||||
ZipFile(const char *filepath);
|
||||
//!Destructor
|
||||
~ZipFile();
|
||||
//!Extract all files from a zip file to a directory
|
||||
//!\param dest Destination path to where to extract
|
||||
bool ExtractAll(const char *dest);
|
||||
protected:
|
||||
bool LoadList();
|
||||
unzFile File;
|
||||
unz_file_info cur_file_info;
|
||||
FileStructure *FileList;
|
||||
class ZipFile
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
ZipFile(const char *filepath);
|
||||
//!Destructor
|
||||
~ZipFile();
|
||||
//!Extract all files from a zip file to a directory
|
||||
//!\param dest Destination path to where to extract
|
||||
bool ExtractAll(const char *dest);
|
||||
protected:
|
||||
bool LoadList();
|
||||
unzFile File;
|
||||
unz_file_info cur_file_info;
|
||||
FileStructure *FileList;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -7,10 +7,10 @@
|
||||
*
|
||||
* Email: crh@ubiqx.mn.org
|
||||
*
|
||||
* $Id: MD5.c,v 0.6 2005/06/08 18:35:59 crh Exp $
|
||||
* $Id: MD5.c,v 0.6 2005/06/08 18:35:59 crh Exp $
|
||||
*
|
||||
*
|
||||
* Modifications and additions by dimok
|
||||
*
|
||||
* Modifications and additions by dimok
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
@ -75,14 +75,14 @@
|
||||
*
|
||||
* ========================================================================== **
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "MD5.h"
|
||||
|
||||
@ -110,26 +110,29 @@
|
||||
* array. They're divided up into four groups of 16.
|
||||
*/
|
||||
|
||||
static const uint8_t K[3][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] = {
|
||||
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] = {
|
||||
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 },
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 },
|
||||
|
||||
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
@ -145,7 +148,7 @@ static const uint32_t T[4][16] = {
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 },
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -165,8 +168,8 @@ static const uint32_t T[4][16] = {
|
||||
#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 GetLongByte( L, idx ) ((unsigned char)(( L >> (((idx) & 0x03) << 3) ) & 0xFF))
|
||||
|
||||
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
|
||||
|
||||
|
||||
@ -175,118 +178,122 @@ static const uint32_t T[4][16] = {
|
||||
*/
|
||||
|
||||
static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
||||
*
|
||||
* Input: ABCD - Pointer to an array of four unsigned longwords.
|
||||
* block - An array of bytes, 64 bytes in size.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* Notes: The MD5 algorithm operates on a set of four longwords stored
|
||||
* (conceptually) in four "registers". It is easy to imagine a
|
||||
* simple MD4/5 chip that would operate this way. In any case,
|
||||
* the mangling of the contents of those registers is driven by
|
||||
* the input message. The message is chopped and finally padded
|
||||
* into 64-byte chunks and each chunk is used to manipulate the
|
||||
* contents of the registers.
|
||||
*
|
||||
* The MD5 Algorithm calls for padding the input to ensure that
|
||||
* it is a multiple of 64 bytes in length. The last 16 bytes
|
||||
* of the padding space are used to store the message length
|
||||
* (the length of the original message, before padding, expressed
|
||||
* in terms of bits). If there is not enough room for 16 bytes
|
||||
* worth of bitcount (eg., if the original message was 122 bytes
|
||||
* long) then the block is padded to the end with zeros and
|
||||
* passed to this function. Then *another* block is filled with
|
||||
* zeros except for the last 16 bytes which contain the length.
|
||||
*
|
||||
* Oh... and the algorithm requires that there be at least one
|
||||
* padding byte. The first padding byte has a value of 0x80,
|
||||
* and any others are 0x00.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int round;
|
||||
int i, j;
|
||||
uint8_t s;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t KeepABCD[4];
|
||||
uint32_t X[16];
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
||||
*
|
||||
* Input: ABCD - Pointer to an array of four unsigned longwords.
|
||||
* block - An array of bytes, 64 bytes in size.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* Notes: The MD5 algorithm operates on a set of four longwords stored
|
||||
* (conceptually) in four "registers". It is easy to imagine a
|
||||
* simple MD4/5 chip that would operate this way. In any case,
|
||||
* the mangling of the contents of those registers is driven by
|
||||
* the input message. The message is chopped and finally padded
|
||||
* into 64-byte chunks and each chunk is used to manipulate the
|
||||
* contents of the registers.
|
||||
*
|
||||
* The MD5 Algorithm calls for padding the input to ensure that
|
||||
* it is a multiple of 64 bytes in length. The last 16 bytes
|
||||
* of the padding space are used to store the message length
|
||||
* (the length of the original message, before padding, expressed
|
||||
* in terms of bits). If there is not enough room for 16 bytes
|
||||
* worth of bitcount (eg., if the original message was 122 bytes
|
||||
* long) then the block is padded to the end with zeros and
|
||||
* passed to this function. Then *another* block is filled with
|
||||
* zeros except for the last 16 bytes which contain the length.
|
||||
*
|
||||
* Oh... and the algorithm requires that there be at least one
|
||||
* padding byte. The first padding byte has a value of 0x80,
|
||||
* and any others are 0x00.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int round;
|
||||
int i, j;
|
||||
uint8_t s;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t KeepABCD[4];
|
||||
uint32_t X[16];
|
||||
|
||||
/* Store the current ABCD values for later re-use.
|
||||
*/
|
||||
for ( i = 0; i < 4; i++ )
|
||||
KeepABCD[i] = ABCD[i];
|
||||
/* 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);
|
||||
/* Convert the input block into an array of unsigned longs, taking care
|
||||
* to read the block in Little Endian order (the algorithm assumes this).
|
||||
* The uint32_t values are then handled in host order.
|
||||
*/
|
||||
for( i = 0, j = 0; i < 16; i++ )
|
||||
{
|
||||
X[i] = (uint32_t)block[j++];
|
||||
X[i] |= ((uint32_t)block[j++] << 8);
|
||||
X[i] |= ((uint32_t)block[j++] << 16);
|
||||
X[i] |= ((uint32_t)block[j++] << 24);
|
||||
}
|
||||
|
||||
/* This loop performs the four rounds of permutations.
|
||||
* The rounds are each very similar. The differences are in three areas:
|
||||
* - The function (F, G, H, or I) used to perform bitwise permutations
|
||||
* on the registers,
|
||||
* - The order in which values from X[] are chosen.
|
||||
* - Changes to the number of bits by which the registers are rotated.
|
||||
* This implementation uses a switch statement to deal with some of the
|
||||
* differences between rounds. Other differences are handled by storing
|
||||
* values in arrays and using the round number to select the correct set
|
||||
* of values.
|
||||
*
|
||||
* (My implementation appears to be a poor compromise between speed, size,
|
||||
* and clarity. Ugh. [crh])
|
||||
*/
|
||||
for ( round = 0; round < 4; round++ ) {
|
||||
for ( i = 0; i < 16; i++ ) {
|
||||
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
|
||||
s = S[round][i%4]; /* <s> is the bit shift for this iteration. */
|
||||
/* This loop performs the four rounds of permutations.
|
||||
* The rounds are each very similar. The differences are in three areas:
|
||||
* - The function (F, G, H, or I) used to perform bitwise permutations
|
||||
* on the registers,
|
||||
* - The order in which values from X[] are chosen.
|
||||
* - Changes to the number of bits by which the registers are rotated.
|
||||
* This implementation uses a switch statement to deal with some of the
|
||||
* differences between rounds. Other differences are handled by storing
|
||||
* values in arrays and using the round number to select the correct set
|
||||
* of values.
|
||||
*
|
||||
* (My implementation appears to be a poor compromise between speed, size,
|
||||
* and clarity. Ugh. [crh])
|
||||
*/
|
||||
for( round = 0; round < 4; round++ )
|
||||
{
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
|
||||
s = S[round][i%4]; /* <s> is the bit shift for this iteration. */
|
||||
|
||||
b = ABCD[(j+1) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */
|
||||
c = ABCD[(j+2) & 0x3]; /* This isn't really necessary, it just looks */
|
||||
d = ABCD[(j+3) & 0x3]; /* clean & will hopefully be optimized away. */
|
||||
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) )));
|
||||
/* 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] );
|
||||
/* 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 */
|
||||
} /* Permute */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -294,321 +301,330 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
*/
|
||||
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
ctx->len = 0;
|
||||
ctx->b_used = 0;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
ctx->len = 0;
|
||||
ctx->b_used = 0;
|
||||
|
||||
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
|
||||
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
|
||||
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
|
||||
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
|
||||
/* 'round. The initial values are those */
|
||||
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
|
||||
/* provides these values as bytes, not as longwords, and the */
|
||||
/* bytes are arranged in little-endian order as if they were */
|
||||
/* the bytes of (little endian) 32-bit ints. That's */
|
||||
/* confusing as all getout (to me, anyway). The values given */
|
||||
/* here are provided as 32-bit values in C language format, */
|
||||
/* so they are endian-agnostic. */
|
||||
return( ctx );
|
||||
} /* auth_md5InitCtx */
|
||||
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
|
||||
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
|
||||
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
|
||||
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
|
||||
/* 'round. The initial values are those */
|
||||
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
|
||||
/* provides these values as bytes, not as longwords, and the */
|
||||
/* bytes are arranged in little-endian order as if they were */
|
||||
/* the bytes of (little endian) 32-bit ints. That's */
|
||||
/* confusing as all getout (to me, anyway). The values given */
|
||||
/* here are provided as 32-bit values in C language format, */
|
||||
/* so they are endian-agnostic. */
|
||||
return( ctx );
|
||||
} /* auth_md5InitCtx */
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Add the new block's length to the total length.
|
||||
*/
|
||||
ctx->len += (uint32_t)len;
|
||||
/* 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;
|
||||
}
|
||||
/* 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 */
|
||||
/* Return the updated context.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5SumCtx */
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
uint32_t l;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
uint32_t l;
|
||||
|
||||
/* Add the required 0x80 padding initiator byte.
|
||||
* The auth_md5SumCtx() function always permutes and resets the context
|
||||
* block when it gets full, so we know that there must be at least one
|
||||
* free byte in the context block.
|
||||
*/
|
||||
ctx->block[ctx->b_used] = 0x80;
|
||||
(ctx->b_used)++;
|
||||
/* 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;
|
||||
/* Zero out any remaining free bytes in the context block.
|
||||
*/
|
||||
for( i = ctx->b_used; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
|
||||
/* We need 8 bytes to store the length field.
|
||||
* If we don't have 8, call Permute() and reset the context block.
|
||||
*/
|
||||
if ( 56 < ctx->b_used ) {
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
for ( i = 0; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
}
|
||||
|
||||
/* Add the total length and perform the final perumation.
|
||||
* Note: The 60'th byte is read from the *original* <ctx->len> value
|
||||
* and shifted to the correct position. This neatly avoids
|
||||
* any MAXINT numeric overflow issues.
|
||||
*/
|
||||
l = ctx->len << 3;
|
||||
for ( i = 0; i < 4; i++ )
|
||||
ctx->block[56+i] |= GetLongByte( l, i );
|
||||
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
|
||||
/* 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 );
|
||||
|
||||
/* 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 );
|
||||
for( i = 0; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
}
|
||||
|
||||
/* Return the context.
|
||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5CloseCtx */
|
||||
/* Add the total length and perform the final perumation.
|
||||
* Note: The 60'th byte is read from the *original* <ctx->len> value
|
||||
* and shifted to the correct position. This neatly avoids
|
||||
* any MAXINT numeric overflow issues.
|
||||
*/
|
||||
l = ctx->len << 3;
|
||||
for( i = 0; i < 4; i++ )
|
||||
ctx->block[56+i] |= GetLongByte( l, i );
|
||||
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
|
||||
/* Now copy the result into the output buffer and we're done.
|
||||
*/
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
dst[ 0+i] = GetLongByte( ctx->ABCD[0], i );
|
||||
dst[ 4+i] = GetLongByte( ctx->ABCD[1], i );
|
||||
dst[ 8+i] = GetLongByte( ctx->ABCD[2], i );
|
||||
dst[12+i] = GetLongByte( ctx->ABCD[3], i );
|
||||
}
|
||||
|
||||
/* Return the context.
|
||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5CloseCtx */
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
(void)auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
(void)auth_md5SumCtx( ctx, src, len ); /* Pass only one block. */
|
||||
(void)auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
|
||||
return( dst ); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
(void)auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
(void)auth_md5SumCtx( ctx, src, len ); /* Pass only one block. */
|
||||
(void)auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
|
||||
return( dst ); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath of the file to be checked
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
FILE * file;
|
||||
unsigned int blksize = 0;
|
||||
unsigned int read = 0;
|
||||
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath of the file to be checked
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
FILE * file;
|
||||
unsigned int blksize = 0;
|
||||
unsigned int read = 0;
|
||||
|
||||
file = fopen(src, "rb");
|
||||
|
||||
if (file==NULL) {
|
||||
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;
|
||||
|
||||
(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);
|
||||
|
||||
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;
|
||||
} /* 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,244 +1,246 @@
|
||||
#ifndef MD5_H
|
||||
#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:
|
||||
*/
|
||||
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;
|
||||
typedef struct
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int ABCD[4];
|
||||
int b_used;
|
||||
unsigned char block[64];
|
||||
} auth_md5Ctx;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath to the file to be MD5'd.
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath to the file to be MD5'd.
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
const char * MD5ToString(const unsigned char *hash, char *dst);
|
||||
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
|
||||
const char * MD5ToString(const unsigned char *hash, char *dst);
|
||||
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* AUTH_MD5_H */
|
||||
|
@ -22,98 +22,106 @@
|
||||
#include "patches/fst.h"
|
||||
#include "usbloader/fstfile.h"
|
||||
|
||||
s32 dump_banner(const u8* discid,const char * dest) {
|
||||
// Mount the disc
|
||||
//Disc_SetWBFS(1, (u8*)discid);
|
||||
Disc_SetUSB(discid);
|
||||
s32 dump_banner(const u8* discid,const char * dest)
|
||||
{
|
||||
// Mount the disc
|
||||
//Disc_SetWBFS(1, (u8*)discid);
|
||||
Disc_SetUSB(discid);
|
||||
|
||||
Disc_Open();
|
||||
Disc_Open();
|
||||
|
||||
u64 offset;
|
||||
s32 ret;
|
||||
u64 offset;
|
||||
s32 ret;
|
||||
|
||||
ret = __Disc_FindPartition(&offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = __Disc_FindPartition(&offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = WDVD_OpenPartition(offset);
|
||||
ret = WDVD_OpenPartition(offset);
|
||||
|
||||
if (ret < 0) {
|
||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0) {
|
||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read where to find the fst.bin
|
||||
u32 *buffer = memalign(32, 0x20);
|
||||
// Read where to find the fst.bin
|
||||
u32 *buffer = memalign(32, 0x20);
|
||||
|
||||
if (buffer == NULL) {
|
||||
//Out of memory
|
||||
return -1;
|
||||
}
|
||||
if (buffer == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
// Read fst.bin
|
||||
void *fstbuffer = memalign(32, buffer[2]*4);
|
||||
FST_ENTRY *fst = (FST_ENTRY *)fstbuffer;
|
||||
// Read fst.bin
|
||||
void *fstbuffer = memalign(32, buffer[2]*4);
|
||||
FST_ENTRY *fst = (FST_ENTRY *)fstbuffer;
|
||||
|
||||
if (fst == NULL) {
|
||||
//Out of memory
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
if (fst == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(fstbuffer, buffer[2]*4, buffer[1]*4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read(fstbuffer, buffer[2]*4, buffer[1]*4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
|
||||
// Search the fst.bin
|
||||
u32 count = fst[0].filelen;
|
||||
int i;
|
||||
u32 index = 0;
|
||||
// Search the fst.bin
|
||||
u32 count = fst[0].filelen;
|
||||
int i;
|
||||
u32 index = 0;
|
||||
|
||||
for (i=1;i<count;i++) {
|
||||
if (strstr(fstfiles(fst, i), "opening.bnr") != NULL) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
for (i=1;i<count;i++)
|
||||
{
|
||||
if (strstr(fstfiles(fst, i), "opening.bnr") != NULL)
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
//opening.bnr not found
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
if (index == 0)
|
||||
{
|
||||
//opening.bnr not found
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load the .bnr
|
||||
u8 *banner = memalign(32, fst[index].filelen);
|
||||
// Load the .bnr
|
||||
u8 *banner = memalign(32, fst[index].filelen);
|
||||
|
||||
if (banner == NULL) {
|
||||
//Out of memory
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
if (banner == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read((void *)banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read((void *)banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
WDVD_Reset();
|
||||
WDVD_ClosePartition();
|
||||
//fatInitDefault();
|
||||
//SDCard_Init();
|
||||
WDVD_SetUSBMode(NULL, 0);
|
||||
FILE *fp = fopen(dest, "wb");
|
||||
if (fp) {
|
||||
fwrite(banner, 1, fst[index].filelen, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
free(fstbuffer);
|
||||
free(banner);
|
||||
//fatInitDefault();
|
||||
//SDCard_Init();
|
||||
WDVD_SetUSBMode(NULL, 0);
|
||||
FILE *fp = fopen(dest, "wb");
|
||||
if(fp)
|
||||
{
|
||||
fwrite(banner, 1, fst[index].filelen, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
free(fstbuffer);
|
||||
free(banner);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,11 @@
|
||||
#define BANNER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
s32 dump_banner(const u8 *discid,const char * dest);
|
||||
s32 dump_banner(const u8 *discid,const char * dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -5,64 +5,66 @@
|
||||
* Shows TPL Banner images
|
||||
***************************************************************************/
|
||||
#include "gui_banner.h"
|
||||
|
||||
GuiBanner::GuiBanner(const char *tplfilepath) {
|
||||
memory = NULL;
|
||||
tplfilesize = 0;
|
||||
|
||||
GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
{
|
||||
memory = NULL;
|
||||
tplfilesize = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
FILE *tplfp = fopen(tplfilepath,"rb");
|
||||
FILE *tplfp = fopen(tplfilepath,"rb");
|
||||
|
||||
if (tplfp !=NULL) {
|
||||
if(tplfp !=NULL) {
|
||||
|
||||
unsigned short heighttemp = 0;
|
||||
unsigned short widthtemp = 0;
|
||||
unsigned short heighttemp = 0;
|
||||
unsigned short widthtemp = 0;
|
||||
|
||||
fseek(tplfp , 0x14, SEEK_SET);
|
||||
fread((void*)&heighttemp,1,2,tplfp);
|
||||
fread((void*)&widthtemp,1,2,tplfp);
|
||||
fseek (tplfp , 0 , SEEK_END);
|
||||
fseek(tplfp , 0x14, SEEK_SET);
|
||||
fread((void*)&heighttemp,1,2,tplfp);
|
||||
fread((void*)&widthtemp,1,2,tplfp);
|
||||
fseek (tplfp , 0 , SEEK_END);
|
||||
tplfilesize = ftell (tplfp);
|
||||
rewind (tplfp);
|
||||
memory = memalign(32, tplfilesize);
|
||||
if (!memory) {
|
||||
if(!memory) {
|
||||
fclose(tplfp);
|
||||
return;
|
||||
}
|
||||
fread(memory, 1, tplfilesize, tplfp);
|
||||
fclose(tplfp);
|
||||
fclose(tplfp);
|
||||
|
||||
TPLFile tplfile;
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||
if (ret < 0) {
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture(&tplfile,0,&texObj);
|
||||
if (ret < 0) {
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
TPL_CloseTPLFile(&tplfile);
|
||||
|
||||
width = widthtemp;
|
||||
height = heighttemp;
|
||||
widescreen = 0;
|
||||
filecheck = true;
|
||||
width = widthtemp;
|
||||
height = heighttemp;
|
||||
widescreen = 0;
|
||||
filecheck = true;
|
||||
|
||||
} else {
|
||||
filecheck = false;
|
||||
fclose(tplfp);
|
||||
filecheck = false;
|
||||
fclose(tplfp);
|
||||
}
|
||||
}
|
||||
|
||||
GuiBanner::GuiBanner(void *mem, u32 len, int w, int h) {
|
||||
if (!mem || !len)
|
||||
GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
{
|
||||
if(!mem || !len)
|
||||
return;
|
||||
memory = mem;
|
||||
tplfilesize = len;
|
||||
@ -74,13 +76,13 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h) {
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||
if (ret < 0) {
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture(&tplfile,0,&texObj);
|
||||
if (ret < 0) {
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
memory = NULL;
|
||||
return;
|
||||
@ -89,22 +91,24 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h) {
|
||||
|
||||
filecheck = true;
|
||||
}
|
||||
|
||||
GuiBanner::~GuiBanner() {
|
||||
if (memory != NULL) {
|
||||
|
||||
GuiBanner::~GuiBanner()
|
||||
{
|
||||
if(memory != NULL) {
|
||||
free(memory);
|
||||
memory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBanner::Draw() {
|
||||
LOCK(this);
|
||||
if (!filecheck ||!this->IsVisible())
|
||||
return;
|
||||
|
||||
float currScale = this->GetScale();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBanner::Draw()
|
||||
{
|
||||
LOCK(this);
|
||||
if(!filecheck ||!this->IsVisible())
|
||||
return;
|
||||
|
||||
float currScale = this->GetScale();
|
||||
|
||||
Menu_DrawTPLImg(this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale*0.80 : currScale, currScale, this->GetAlpha(), xx1,yy1,xx2,yy2,xx3,yy3,xx4,yy4);
|
||||
|
||||
this->UpdateEffects();
|
||||
}
|
||||
|
||||
this->UpdateEffects();
|
||||
}
|
||||
|
@ -10,24 +10,25 @@
|
||||
|
||||
#include "libwiigui/gui.h"
|
||||
|
||||
class GuiBanner : public GuiImage {
|
||||
class GuiBanner : public GuiImage
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param tplfilepath Path of the tpl file
|
||||
GuiBanner(const char *tplfilepath);
|
||||
GuiBanner(const char *tplfilepath);
|
||||
//!Constructor
|
||||
//!\param mem Memory of the loaded tpl
|
||||
//!\param len Filesize of the tpl
|
||||
//!\param w Width of the tpl
|
||||
//!\param h Height of the tpl
|
||||
GuiBanner(void *mem, u32 len, int w, int h);
|
||||
GuiBanner(void *mem, u32 len, int w, int h);
|
||||
//!Destructor
|
||||
~GuiBanner();
|
||||
void Draw();
|
||||
~GuiBanner();
|
||||
void Draw();
|
||||
protected:
|
||||
void * memory;
|
||||
bool filecheck;
|
||||
u32 tplfilesize;
|
||||
bool filecheck;
|
||||
u32 tplfilesize;
|
||||
GXTexObj texObj;
|
||||
};
|
||||
|
||||
|
@ -28,39 +28,47 @@
|
||||
#include "../ramdisk/ramdisk.h"
|
||||
#include "../listfiles.h"
|
||||
|
||||
u16 be16(const u8 *p) {
|
||||
return (p[0] << 8) | p[1];
|
||||
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];
|
||||
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 be64(const u8 *p)
|
||||
{
|
||||
return ((u64)be32(p) << 32) | be32(p + 4);
|
||||
}
|
||||
|
||||
u64 be34(const u8 *p) {
|
||||
return 4 * (u64)be32(p);
|
||||
u64 be34(const u8 *p)
|
||||
{
|
||||
return 4 * (u64)be32(p);
|
||||
}
|
||||
|
||||
void wbe16(u8 *p, u16 x) {
|
||||
p[0] = x >> 8;
|
||||
p[1] = x;
|
||||
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 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 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);
|
||||
void md5(u8 *data, u32 len, u8 *hash)
|
||||
{
|
||||
MD5(hash, data, len);
|
||||
}
|
||||
|
||||
|
||||
@ -82,416 +90,440 @@ typedef struct {
|
||||
} 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;
|
||||
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
|
||||
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];
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
in_ptr = data;
|
||||
data_end = data + data_size;
|
||||
|
||||
// Assume this for now and grow when needed
|
||||
unpacked_size = 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;
|
||||
decompressed_data = malloc(unpacked_size);
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
|
||||
out_ptr = decompressed_data;
|
||||
out_ptr = decompressed_data;
|
||||
|
||||
while (in_ptr < data_end) {
|
||||
int bit;
|
||||
u8 bitmask = *in_ptr;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
*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;
|
||||
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;
|
||||
u8 *decompressed_data;
|
||||
size_t decompressed_size;
|
||||
|
||||
tag = be32((u8*) &header->imd5_tag);
|
||||
if (tag != 0x494D4435) {
|
||||
return -4;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
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(&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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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 == 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 (type != 0x0000) {
|
||||
free(string_table);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (current_offset < my_data_offset) {
|
||||
int diff = my_data_offset - current_offset;
|
||||
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;
|
||||
if (diff > 32) {
|
||||
free(string_table);
|
||||
return -3;
|
||||
}
|
||||
fread(padding, 1, diff, fp);
|
||||
current_offset += diff;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
||||
chdir("..");
|
||||
dir_index--;
|
||||
}
|
||||
free(string_table);
|
||||
}
|
||||
free(string_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extractbnrfile(const char * filepath, const char * destpath) {
|
||||
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) {
|
||||
subfoldercreate(destpath);
|
||||
chdir(destpath);
|
||||
FILE *fp = fopen(filepath, "rb");
|
||||
if(fp)
|
||||
{
|
||||
subfoldercreate(destpath);
|
||||
chdir(destpath);
|
||||
|
||||
do_imet_header(fp);
|
||||
ret = do_U8_archive(fp);
|
||||
do_imet_header(fp);
|
||||
ret = do_U8_archive(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
return ret;
|
||||
fclose(fp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unpackBin(const char * filename,const char * outdir) {
|
||||
FILE *fp = fopen(filename,"rb");;
|
||||
if (fp) {
|
||||
subfoldercreate(outdir);
|
||||
chdir(outdir);
|
||||
int unpackBin(const char * filename,const char * outdir)
|
||||
{
|
||||
FILE *fp = fopen(filename,"rb");;
|
||||
if(fp)
|
||||
{
|
||||
subfoldercreate(outdir);
|
||||
chdir(outdir);
|
||||
|
||||
do_U8_archivebanner(fp);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
do_U8_archivebanner(fp);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
return 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) {
|
||||
int unpackBanner(const u8 *gameid, int what, const char *outdir)
|
||||
{
|
||||
|
||||
char path[256];
|
||||
if (!ramdiskMount("BANNER", NULL)) return -1;
|
||||
char path[256];
|
||||
if(!ramdiskMount("BANNER", NULL)) return -1;
|
||||
|
||||
subfoldercreate(TMP_PATH("/"));
|
||||
s32 ret = dump_banner(gameid, TMP_PATH("/opening.bnr"));
|
||||
if (ret != 1) {
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
subfoldercreate(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;
|
||||
}
|
||||
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");
|
||||
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;
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
@ -9,35 +9,36 @@
|
||||
#define _OPENINGBNR_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
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
|
||||
************************************************************/
|
||||
/***********************************************************
|
||||
* 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);
|
||||
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);
|
||||
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);
|
||||
u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size);
|
||||
|
||||
u16 be16(const u8 *p);
|
||||
u32 be32(const u8 *p);
|
||||
u16 be16(const u8 *p);
|
||||
u32 be32(const u8 *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -11,177 +11,199 @@
|
||||
#include "bannersound.h"
|
||||
|
||||
|
||||
struct IMD5Header {
|
||||
u32 fcc;
|
||||
u32 filesize;
|
||||
u8 zeroes[8];
|
||||
u8 crypto[16];
|
||||
struct IMD5Header
|
||||
{
|
||||
u32 fcc;
|
||||
u32 filesize;
|
||||
u8 zeroes[8];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct IMETHeader {
|
||||
u8 zeroes[64];
|
||||
u32 fcc;
|
||||
u8 unk[8];
|
||||
u32 iconSize;
|
||||
u32 bannerSize;
|
||||
u32 soundSize;
|
||||
u32 flag1;
|
||||
u8 names[7][84];
|
||||
u8 zeroes_2[0x348];
|
||||
u8 crypto[16];
|
||||
struct IMETHeader
|
||||
{
|
||||
u8 zeroes[64];
|
||||
u32 fcc;
|
||||
u8 unk[8];
|
||||
u32 iconSize;
|
||||
u32 bannerSize;
|
||||
u32 soundSize;
|
||||
u32 flag1;
|
||||
u8 names[7][84];
|
||||
u8 zeroes_2[0x348];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct U8Header {
|
||||
u32 fcc;
|
||||
u32 rootNodeOffset;
|
||||
u32 headerSize;
|
||||
u32 dataOffset;
|
||||
u8 zeroes[16];
|
||||
struct U8Header
|
||||
{
|
||||
u32 fcc;
|
||||
u32 rootNodeOffset;
|
||||
u32 headerSize;
|
||||
u32 dataOffset;
|
||||
u8 zeroes[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct U8Entry {
|
||||
struct {
|
||||
u32 fileType :
|
||||
8;
|
||||
u32 nameOffset :
|
||||
24;
|
||||
};
|
||||
u32 fileOffset;
|
||||
union {
|
||||
u32 fileLength;
|
||||
u32 numEntries;
|
||||
};
|
||||
struct U8Entry
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 fileType : 8;
|
||||
u32 nameOffset : 24;
|
||||
};
|
||||
u32 fileOffset;
|
||||
union
|
||||
{
|
||||
u32 fileLength;
|
||||
u32 numEntries;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
struct LZ77Info {
|
||||
u16 length :
|
||||
4;
|
||||
u16 offset :
|
||||
12;
|
||||
struct LZ77Info
|
||||
{
|
||||
u16 length : 4;
|
||||
u16 offset : 12;
|
||||
} __attribute__((packed));
|
||||
|
||||
static char *u8Filename(const U8Entry *fst, int i) {
|
||||
return (char *)(fst + fst[0].numEntries) + fst[i].nameOffset;
|
||||
static char *u8Filename(const U8Entry *fst, int i)
|
||||
{
|
||||
return (char *)(fst + fst[0].numEntries) + fst[i].nameOffset;
|
||||
}
|
||||
|
||||
inline u32 le32(u32 i) {
|
||||
return ((i & 0xFF) << 24) | ((i & 0xFF00) << 8) | ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24);
|
||||
inline u32 le32(u32 i)
|
||||
{
|
||||
return ((i & 0xFF) << 24) | ((i & 0xFF00) << 8) | ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
inline u16 le16(u16 i) {
|
||||
return ((i & 0xFF) << 8) | ((i & 0xFF00) >> 8);
|
||||
inline u16 le16(u16 i)
|
||||
{
|
||||
return ((i & 0xFF) << 8) | ((i & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size) {
|
||||
u8 *buffer = NULL;
|
||||
if (inLength <= 0x8 || *((const u32 *)inBuf) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10)
|
||||
return NULL;
|
||||
u32 uncSize = le32(((const u32 *)inBuf)[1] << 8);
|
||||
static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size)
|
||||
{
|
||||
u8 *buffer = NULL;
|
||||
if (inLength <= 0x8 || *((const u32 *)inBuf) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10)
|
||||
return NULL;
|
||||
u32 uncSize = le32(((const u32 *)inBuf)[1] << 8);
|
||||
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new(std::nothrow) u8[uncSize];
|
||||
if (!buffer)
|
||||
return buffer;
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new(std::nothrow) u8[uncSize];
|
||||
if (!buffer)
|
||||
return buffer;
|
||||
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
|
||||
while (bufCur < bufEnd && inBuf < inBufEnd) {
|
||||
u8 flags = *inBuf;
|
||||
++inBuf;
|
||||
for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i) {
|
||||
if ((flags & 0x80) != 0) {
|
||||
const LZ77Info &info = *(const LZ77Info *)inBuf;
|
||||
inBuf += sizeof (LZ77Info);
|
||||
int length = info.length + 3;
|
||||
if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd)
|
||||
return buffer;
|
||||
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||
bufCur += length;
|
||||
} else {
|
||||
*bufCur = *inBuf;
|
||||
++inBuf;
|
||||
++bufCur;
|
||||
}
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
size = uncSize;
|
||||
return buffer;
|
||||
while (bufCur < bufEnd && inBuf < inBufEnd)
|
||||
{
|
||||
u8 flags = *inBuf;
|
||||
++inBuf;
|
||||
for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i)
|
||||
{
|
||||
if ((flags & 0x80) != 0)
|
||||
{
|
||||
const LZ77Info &info = *(const LZ77Info *)inBuf;
|
||||
inBuf += sizeof (LZ77Info);
|
||||
int length = info.length + 3;
|
||||
if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd)
|
||||
return buffer;
|
||||
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||
bufCur += length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bufCur = *inBuf;
|
||||
++inBuf;
|
||||
++bufCur;
|
||||
}
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
size = uncSize;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const u8 *LoadBannerSound(const u8 *discid, u32 *size) {
|
||||
if (!discid)
|
||||
const u8 *LoadBannerSound(const u8 *discid, u32 *size)
|
||||
{
|
||||
if(!discid)
|
||||
return NULL;
|
||||
|
||||
Disc_SetUSB(NULL);
|
||||
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) discid);
|
||||
if (!disc) {
|
||||
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
||||
Disc_SetUSB(NULL);
|
||||
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) discid);
|
||||
if(!disc)
|
||||
{
|
||||
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
wiidisc_t *wdisc = wd_open_disc((int (*)(void *, u32, u32, void *))wbfs_disc_read, disc);
|
||||
if (!wdisc) {
|
||||
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
||||
}
|
||||
wiidisc_t *wdisc = wd_open_disc((int (*)(void *, u32, u32, void *))wbfs_disc_read, disc);
|
||||
if(!wdisc)
|
||||
{
|
||||
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
u8 * opening_bnr = wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr");
|
||||
if (!opening_bnr) {
|
||||
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
||||
}
|
||||
u8 * opening_bnr = wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr");
|
||||
if(!opening_bnr)
|
||||
{
|
||||
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wd_close_disc(wdisc);
|
||||
WBFS_CloseDisc(disc);
|
||||
wd_close_disc(wdisc);
|
||||
WBFS_CloseDisc(disc);
|
||||
|
||||
const U8Entry *fst;
|
||||
const U8Entry *fst;
|
||||
|
||||
const IMETHeader *imetHdr = (IMETHeader *)opening_bnr;
|
||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ ) {
|
||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
const IMETHeader *imetHdr = (IMETHeader *)opening_bnr;
|
||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
const U8Header *bnrArcHdr = (U8Header *)(imetHdr + 1);
|
||||
}
|
||||
const U8Header *bnrArcHdr = (U8Header *)(imetHdr + 1);
|
||||
|
||||
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) {
|
||||
/* Not all games have a sound.bin and this message is annoying **/
|
||||
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
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)
|
||||
{
|
||||
/* Not all games have a sound.bin and this message is annoying **/
|
||||
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
const u8 *sound_bin = ((const u8 *)bnrArcHdr) + fst[i].fileOffset;
|
||||
if ( ((IMD5Header *)sound_bin)->fcc != 0x494D4435 /*"IMD5"*/ ) {
|
||||
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
}
|
||||
const u8 *sound_bin = ((const u8 *)bnrArcHdr) + fst[i].fileOffset;
|
||||
if ( ((IMD5Header *)sound_bin)->fcc != 0x494D4435 /*"IMD5"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
const u8 *soundChunk = sound_bin + sizeof (IMD5Header);;
|
||||
u32 soundChunkSize = fst[i].fileLength - sizeof (IMD5Header);
|
||||
}
|
||||
const u8 *soundChunk = sound_bin + sizeof (IMD5Header);;
|
||||
u32 soundChunkSize = fst[i].fileLength - sizeof (IMD5Header);
|
||||
|
||||
if ( *((u32*)soundChunk) == 0x4C5A3737 /*"LZ77"*/ ) {
|
||||
u32 uncSize = NULL;
|
||||
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize);
|
||||
if (!uncompressed_data) {
|
||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
if (size) *size=uncSize;
|
||||
free(opening_bnr);
|
||||
return uncompressed_data;
|
||||
}
|
||||
u8 *out = new(std::nothrow) u8[soundChunkSize];
|
||||
if (out) {
|
||||
memcpy(out, soundChunk, soundChunkSize);
|
||||
if (size) *size=soundChunkSize;
|
||||
}
|
||||
free(opening_bnr);
|
||||
return out;
|
||||
if ( *((u32*)soundChunk) == 0x4C5A3737 /*"LZ77"*/ )
|
||||
{
|
||||
u32 uncSize = NULL;
|
||||
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize);
|
||||
if (!uncompressed_data)
|
||||
{
|
||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
if(size) *size=uncSize;
|
||||
free(opening_bnr);
|
||||
return uncompressed_data;
|
||||
}
|
||||
u8 *out = new(std::nothrow) u8[soundChunkSize];
|
||||
if(out)
|
||||
{
|
||||
memcpy(out, soundChunk, soundChunkSize);
|
||||
if(size) *size=soundChunkSize;
|
||||
}
|
||||
free(opening_bnr);
|
||||
return out;
|
||||
}
|
||||
|
@ -24,140 +24,142 @@ extern GuiWindow * mainWindow;
|
||||
* CheatMenu
|
||||
***************************************************************************/
|
||||
int CheatMenu(const char * gameID) {
|
||||
int choice = 0;
|
||||
bool exit = false;
|
||||
int ret = 1;
|
||||
int choice = 0;
|
||||
bool exit = false;
|
||||
int ret = 1;
|
||||
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if (!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
|
||||
char imgPath[100];
|
||||
snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path);
|
||||
GuiImageData btnOutline(imgPath, button_dialogue_box_png);
|
||||
snprintf(imgPath, sizeof(imgPath), "%ssettings_background.png", CFG.theme_path);
|
||||
GuiImageData settingsbg(imgPath, settings_background_png);
|
||||
GuiImage settingsbackground(&settingsbg);
|
||||
char imgPath[100];
|
||||
snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path);
|
||||
GuiImageData btnOutline(imgPath, button_dialogue_box_png);
|
||||
snprintf(imgPath, sizeof(imgPath), "%ssettings_background.png", CFG.theme_path);
|
||||
GuiImageData settingsbg(imgPath, settings_background_png);
|
||||
GuiImage settingsbackground(&settingsbg);
|
||||
|
||||
GuiTrigger trigA;
|
||||
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
|
||||
GuiTrigger trigB;
|
||||
trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B);
|
||||
GuiTrigger trigA;
|
||||
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
|
||||
GuiTrigger trigB;
|
||||
trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B);
|
||||
|
||||
GuiText backBtnTxt(tr("Back") , 22, THEME.prompttext);
|
||||
backBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage backBtnImg(&btnOutline);
|
||||
GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2,1);
|
||||
backBtn.SetLabel(&backBtnTxt);
|
||||
backBtn.SetTrigger(&trigB);
|
||||
GuiText backBtnTxt(tr("Back") , 22, THEME.prompttext);
|
||||
backBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage backBtnImg(&btnOutline);
|
||||
GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2,1);
|
||||
backBtn.SetLabel(&backBtnTxt);
|
||||
backBtn.SetTrigger(&trigB);
|
||||
|
||||
GuiText createBtnTxt(tr("Create") , 22, THEME.prompttext);
|
||||
createBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage createBtnImg(&btnOutline);
|
||||
GuiButton createBtn(&createBtnImg,&createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2,1);
|
||||
createBtn.SetLabel(&createBtnTxt);
|
||||
GuiText createBtnTxt(tr("Create") , 22, THEME.prompttext);
|
||||
createBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage createBtnImg(&btnOutline);
|
||||
GuiButton createBtn(&createBtnImg,&createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2,1);
|
||||
createBtn.SetLabel(&createBtnTxt);
|
||||
|
||||
char txtfilename[55];
|
||||
snprintf(txtfilename,sizeof(txtfilename),"%s%s.txt",Settings.TxtCheatcodespath,gameID);
|
||||
char txtfilename[55];
|
||||
snprintf(txtfilename,sizeof(txtfilename),"%s%s.txt",Settings.TxtCheatcodespath,gameID);
|
||||
|
||||
GCTCheats c;
|
||||
int check = c.openTxtfile(txtfilename);
|
||||
GCTCheats c;
|
||||
int check = c.openTxtfile(txtfilename);
|
||||
|
||||
int download =0;
|
||||
int download =0;
|
||||
|
||||
switch (check) {
|
||||
case -1:
|
||||
WindowPrompt(tr("Error"),tr("Cheatfile is blank"),tr("OK"));
|
||||
break;
|
||||
case 0:
|
||||
download = WindowPrompt(tr("Error"),tr("No Cheatfile found"),tr("Download Now"),tr("Cancel"));
|
||||
if (download==1) {
|
||||
download = CodeDownload(gameID);
|
||||
if (download < 0 || c.openTxtfile(txtfilename) != 1)
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
case 1:
|
||||
int cntcheats = c.getCnt();
|
||||
customOptionList cheatslst(cntcheats);
|
||||
GuiCustomOptionBrowser chtBrowser(400, 280, &cheatslst, CFG.theme_path, "bg_options_settings.png", bg_options_settings_png, 1, 90);
|
||||
chtBrowser.SetPosition(0, 90);
|
||||
chtBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
chtBrowser.SetClickable(true);
|
||||
switch (check) {
|
||||
case -1:
|
||||
WindowPrompt(tr("Error"),tr("Cheatfile is blank"),tr("OK"));
|
||||
break;
|
||||
case 0:
|
||||
download = WindowPrompt(tr("Error"),tr("No Cheatfile found"),tr("Download Now"),tr("Cancel"));
|
||||
if (download==1)
|
||||
{
|
||||
download = CodeDownload(gameID);
|
||||
if(download < 0 || c.openTxtfile(txtfilename) != 1)
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
case 1:
|
||||
int cntcheats = c.getCnt();
|
||||
customOptionList cheatslst(cntcheats);
|
||||
GuiCustomOptionBrowser chtBrowser(400, 280, &cheatslst, CFG.theme_path, "bg_options_settings.png", bg_options_settings_png, 1, 90);
|
||||
chtBrowser.SetPosition(0, 90);
|
||||
chtBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
chtBrowser.SetClickable(true);
|
||||
|
||||
GuiText titleTxt(c.getGameName().c_str(), 28, (GXColor) {0, 0, 0, 255});
|
||||
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
titleTxt.SetMaxWidth(350, GuiText::SCROLL);
|
||||
titleTxt.SetPosition(12,40);
|
||||
GuiText titleTxt(c.getGameName().c_str(), 28, (GXColor) {0, 0, 0, 255});
|
||||
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
titleTxt.SetMaxWidth(350, GuiText::SCROLL);
|
||||
titleTxt.SetPosition(12,40);
|
||||
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
cheatslst.SetValue(i, "%s",c.getCheatName(i).c_str());
|
||||
cheatslst.SetName(i, "OFF");
|
||||
}
|
||||
|
||||
HaltGui();
|
||||
GuiWindow w(screenwidth, screenheight);
|
||||
w.Append(&settingsbackground);
|
||||
w.Append(&titleTxt);
|
||||
w.Append(&backBtn);
|
||||
w.Append(&createBtn);
|
||||
w.Append(&chtBrowser);
|
||||
mainWindow->SetState(STATE_DISABLED);
|
||||
mainWindow->ChangeFocus(&w);
|
||||
mainWindow->Append(&w);
|
||||
ResumeGui();
|
||||
HaltGui();
|
||||
GuiWindow w(screenwidth, screenheight);
|
||||
w.Append(&settingsbackground);
|
||||
w.Append(&titleTxt);
|
||||
w.Append(&backBtn);
|
||||
w.Append(&createBtn);
|
||||
w.Append(&chtBrowser);
|
||||
mainWindow->SetState(STATE_DISABLED);
|
||||
mainWindow->ChangeFocus(&w);
|
||||
mainWindow->Append(&w);
|
||||
ResumeGui();
|
||||
|
||||
while (!exit) {
|
||||
VIDEO_WaitVSync ();
|
||||
while (!exit) {
|
||||
VIDEO_WaitVSync ();
|
||||
|
||||
ret = chtBrowser.GetClickedOption();
|
||||
if (ret != -1) {
|
||||
const char *strCheck = cheatslst.GetName(ret);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
cheatslst.SetName(ret,"%s","OFF");
|
||||
} else if (strncmp(strCheck,"OFF",3) == 0) {
|
||||
cheatslst.SetName(ret,"%s","ON");
|
||||
}
|
||||
}
|
||||
ret = chtBrowser.GetClickedOption();
|
||||
if (ret != -1) {
|
||||
const char *strCheck = cheatslst.GetName(ret);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
cheatslst.SetName(ret,"%s","OFF");
|
||||
} else if (strncmp(strCheck,"OFF",3) == 0) {
|
||||
cheatslst.SetName(ret,"%s","ON");
|
||||
}
|
||||
}
|
||||
|
||||
if (createBtn.GetState() == STATE_CLICKED) {
|
||||
createBtn.ResetState();
|
||||
if (cntcheats > 0) {
|
||||
int selectednrs[30];
|
||||
int x = 0;
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
const char *strCheck = cheatslst.GetName(i);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
selectednrs[x] = i;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
if (x == 0) {
|
||||
WindowPrompt(tr("Error"),tr("No cheats were selected"),tr("OK"));
|
||||
} else {
|
||||
subfoldercreate(Settings.Cheatcodespath);
|
||||
string chtpath = Settings.Cheatcodespath;
|
||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||
c.createGCT(selectednrs,x,gctfname.c_str());
|
||||
WindowPrompt(tr("GCT File created"),NULL,tr("OK"));
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK"));
|
||||
}
|
||||
if (createBtn.GetState() == STATE_CLICKED) {
|
||||
createBtn.ResetState();
|
||||
if (cntcheats > 0) {
|
||||
int selectednrs[30];
|
||||
int x = 0;
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
const char *strCheck = cheatslst.GetName(i);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
selectednrs[x] = i;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
if (x == 0) {
|
||||
WindowPrompt(tr("Error"),tr("No cheats were selected"),tr("OK"));
|
||||
} else {
|
||||
subfoldercreate(Settings.Cheatcodespath);
|
||||
string chtpath = Settings.Cheatcodespath;
|
||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||
c.createGCT(selectednrs,x,gctfname.c_str());
|
||||
WindowPrompt(tr("GCT File created"),NULL,tr("OK"));
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK"));
|
||||
}
|
||||
|
||||
if (backBtn.GetState() == STATE_CLICKED) {
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HaltGui();
|
||||
mainWindow->SetState(STATE_DEFAULT);
|
||||
mainWindow->Remove(&w);
|
||||
ResumeGui();
|
||||
break;
|
||||
}
|
||||
if (backBtn.GetState() == STATE_CLICKED) {
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HaltGui();
|
||||
mainWindow->SetState(STATE_DEFAULT);
|
||||
mainWindow->Remove(&w);
|
||||
ResumeGui();
|
||||
break;
|
||||
}
|
||||
|
||||
return choice;
|
||||
return choice;
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ string GCTCheats::getCheatComment(int nr) {
|
||||
|
||||
int GCTCheats::createGCT(int nr,const char * filename) {
|
||||
|
||||
if (nr == 0)
|
||||
return 0;
|
||||
if (nr == 0)
|
||||
return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
@ -132,8 +132,8 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
|
||||
int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
||||
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
@ -185,54 +185,54 @@ int GCTCheats::openTxtfile(const char * filename) {
|
||||
filestr.seekg(0,ios_base::beg);
|
||||
|
||||
getline(filestr,sGameID);
|
||||
if (sGameID[sGameID.length() - 1] == '\r')
|
||||
sGameID.erase(sGameID.length() - 1);
|
||||
|
||||
if (sGameID[sGameID.length() - 1] == '\r')
|
||||
sGameID.erase(sGameID.length() - 1);
|
||||
|
||||
getline(filestr,sGameTitle);
|
||||
if (sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
sGameTitle.erase(sGameTitle.length() - 1);
|
||||
|
||||
if (sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
sGameTitle.erase(sGameTitle.length() - 1);
|
||||
|
||||
getline(filestr,sCheatName[i]); // skip first line if file uses CRLF
|
||||
if (!sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
filestr.seekg(0,ios_base::beg);
|
||||
if (!sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
filestr.seekg(0,ios_base::beg);
|
||||
|
||||
while (!filestr.eof()) {
|
||||
getline(filestr,sCheatName[i]); // '\n' delimiter by default
|
||||
if (sCheatName[i][sCheatName[i].length() - 1] == '\r')
|
||||
sCheatName[i].erase(sCheatName[i].length() - 1);
|
||||
if (sCheatName[i][sCheatName[i].length() - 1] == '\r')
|
||||
sCheatName[i].erase(sCheatName[i].length() - 1);
|
||||
|
||||
string cheatdata;
|
||||
bool emptyline = false;
|
||||
|
||||
do {
|
||||
getline(filestr,str);
|
||||
if (str[str.length() - 1] == '\r')
|
||||
str.erase(str.length() - 1);
|
||||
|
||||
getline(filestr,str);
|
||||
if (str[str.length() - 1] == '\r')
|
||||
str.erase(str.length() - 1);
|
||||
|
||||
if (str == "" || str[0] == '\r' || str[0] == '\n') {
|
||||
emptyline = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsCode(str)) {
|
||||
// remove any garbage (comment) after code
|
||||
while (str.size() > 17) {
|
||||
str.erase(str.length() - 1);
|
||||
}
|
||||
cheatdata.append(str);
|
||||
// remove any garbage (comment) after code
|
||||
while (str.size() > 17) {
|
||||
str.erase(str.length() - 1);
|
||||
}
|
||||
cheatdata.append(str);
|
||||
size_t found=cheatdata.find(' ');
|
||||
cheatdata.replace(found,1,"");
|
||||
} else {
|
||||
} else {
|
||||
//printf("%i",str.size());
|
||||
sCheatComment[i] = str;
|
||||
}
|
||||
if (filestr.eof()) break;
|
||||
|
||||
if (filestr.eof()) break;
|
||||
|
||||
} while (!emptyline);
|
||||
|
||||
sCheats[i] = cheatdata;
|
||||
i++;
|
||||
if (i == MAXCHEATS) break;
|
||||
i++;
|
||||
if (i == MAXCHEATS) break;
|
||||
}
|
||||
iCntCheats = i;
|
||||
filestr.close();
|
||||
@ -240,15 +240,15 @@ int GCTCheats::openTxtfile(const char * filename) {
|
||||
}
|
||||
|
||||
bool GCTCheats::IsCode(const std::string& str) {
|
||||
if (str[8] == ' ' && str.size() >= 17) {
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf(part1,sizeof(part1),"%c%c%c%c%c%c%c%c",str[0],str[1],str[2],str[3],str[4],str[5],str[6],str[7]);
|
||||
snprintf(part1,sizeof(part2),"%c%c%c%c%c%c%c%c",str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16]);
|
||||
if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (str[8] == ' ' && str.size() >= 17) {
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf(part1,sizeof(part1),"%c%c%c%c%c%c%c%c",str[0],str[1],str[2],str[3],str[4],str[5],str[6],str[7]);
|
||||
snprintf(part1,sizeof(part2),"%c%c%c%c%c%c%c%c",str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16]);
|
||||
if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* gct.h
|
||||
* Class to handle Ocarina TXT Cheatfiles
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GCT_H
|
||||
@ -66,9 +66,9 @@ public:
|
||||
//!Gets Cheat Comment
|
||||
//!\return Cheat Comment
|
||||
string getCheatComment(int nr);
|
||||
//!Check if string is a code
|
||||
//!Check if string is a code
|
||||
//!\return true/false
|
||||
bool IsCode(const std::string& s);
|
||||
bool IsCode(const std::string& s);
|
||||
};
|
||||
|
||||
#endif /* _GCT_H */
|
||||
|
BIN
source/data1
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 22 KiB |
@ -43,34 +43,34 @@ int fs_ntfs_mount = 0;
|
||||
sec_t fs_ntfs_sec = 0;
|
||||
|
||||
int USBDevice_Init() {
|
||||
gprintf("\nUSBDevice_Init()");
|
||||
gprintf("\nUSBDevice_Init()");
|
||||
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("USB:/");
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//try first mount with cIOS
|
||||
//try first mount with cIOS
|
||||
if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("USB", &__io_usbstorage, 0, CACHE, SECTORS)) {
|
||||
gprintf(":-1");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fat_usb_mount = 1;
|
||||
fat_usb_sec = _FAT_startSector;
|
||||
gprintf(":0");
|
||||
return 0;
|
||||
//try now mount with libogc
|
||||
if (!fatMount("USB", &__io_usbstorage, 0, CACHE, SECTORS)) {
|
||||
gprintf(":-1");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fat_usb_mount = 1;
|
||||
fat_usb_sec = _FAT_startSector;
|
||||
gprintf(":0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBDevice_deInit() {
|
||||
gprintf("\nUSBDevice_deInit()");
|
||||
gprintf("\nUSBDevice_deInit()");
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("USB:/");
|
||||
|
||||
fat_usb_mount = 0;
|
||||
fat_usb_sec = 0;
|
||||
fat_usb_mount = 0;
|
||||
fat_usb_sec = 0;
|
||||
}
|
||||
|
||||
int WBFSDevice_Init(u32 sector) {
|
||||
@ -78,29 +78,29 @@ int WBFSDevice_Init(u32 sector) {
|
||||
fatUnmount("WBFS:/");
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//try first mount with cIOS
|
||||
if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage, 0, CACHE, SECTORS)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//try first mount with cIOS
|
||||
if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage, 0, CACHE, SECTORS)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fat_wbfs_mount = 1;
|
||||
fat_wbfs_sec = _FAT_startSector;
|
||||
if (sector && fat_wbfs_sec != sector) {
|
||||
// This is an error situation...actually, but is ignored in Config loader also
|
||||
// Should ask Oggzee about it...
|
||||
}
|
||||
return 0;
|
||||
fat_wbfs_mount = 1;
|
||||
fat_wbfs_sec = _FAT_startSector;
|
||||
if (sector && fat_wbfs_sec != sector) {
|
||||
// This is an error situation...actually, but is ignored in Config loader also
|
||||
// Should ask Oggzee about it...
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WBFSDevice_deInit() {
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("WBFS:/");
|
||||
|
||||
fat_wbfs_mount = 0;
|
||||
fat_wbfs_sec = 0;
|
||||
fat_wbfs_mount = 0;
|
||||
fat_wbfs_sec = 0;
|
||||
}
|
||||
|
||||
int isInserted(const char *path) {
|
||||
@ -111,118 +111,128 @@ int isInserted(const char *path) {
|
||||
}
|
||||
|
||||
int SDCard_Init() {
|
||||
gprintf("\nSDCard_Init()");
|
||||
gprintf("\nSDCard_Init()");
|
||||
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("SD:/");
|
||||
//right now mounts first FAT-partition
|
||||
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) {
|
||||
fat_sd_mount = MOUNT_SD;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
gprintf(":1");
|
||||
return 1;
|
||||
} else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) {
|
||||
fat_sd_mount = MOUNT_SDHC;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
gprintf(":1");
|
||||
return 1;
|
||||
}
|
||||
gprintf(":-1");
|
||||
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) {
|
||||
fat_sd_mount = MOUNT_SD;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
gprintf(":1");
|
||||
return 1;
|
||||
}
|
||||
else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) {
|
||||
fat_sd_mount = MOUNT_SDHC;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
gprintf(":1");
|
||||
return 1;
|
||||
}
|
||||
gprintf(":-1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SDCard_deInit() {
|
||||
gprintf("\nSDCard_deInit()");
|
||||
gprintf("\nSDCard_deInit()");
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("SD:/");
|
||||
|
||||
fat_sd_mount = MOUNT_NONE;
|
||||
fat_sd_sec = 0;
|
||||
fat_sd_mount = MOUNT_NONE;
|
||||
fat_sd_sec = 0;
|
||||
}
|
||||
|
||||
void ntfsInit();
|
||||
|
||||
s32 MountNTFS(u32 sector) {
|
||||
s32 ret;
|
||||
s32 MountNTFS(u32 sector)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
if (fs_ntfs_mount) return 0;
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
if (fs_ntfs_mount) return 0;
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
|
||||
ntfsInit(); // Call ntfs init here, to prevent locale resets
|
||||
ntfsInit(); // Call ntfs init here, to prevent locale resets
|
||||
|
||||
// ntfsInit resets locale settings
|
||||
// which breaks unicode in console
|
||||
// so we change it back to C-UTF-8
|
||||
setlocale(LC_CTYPE, "C-UTF-8");
|
||||
setlocale(LC_MESSAGES, "C-UTF-8");
|
||||
|
||||
// ntfsInit resets locale settings
|
||||
// which breaks unicode in console
|
||||
// so we change it back to C-UTF-8
|
||||
setlocale(LC_CTYPE, "C-UTF-8");
|
||||
setlocale(LC_MESSAGES, "C-UTF-8");
|
||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
||||
/* Initialize WBFS interface */
|
||||
if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage.startup();
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Mount device */
|
||||
if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount("NTFS", &__io_usbstorage, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
if (!ret) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
} else if (wbfsDev == WBFS_DEVICE_SDHC) {
|
||||
if (sdhc_mode_sd == 0) {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
} else {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
}
|
||||
if (!ret) {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
||||
/* Initialize WBFS interface */
|
||||
if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage.startup();
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Mount device */
|
||||
if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount("NTFS", &__io_usbstorage, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
if (!ret) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
} else if (wbfsDev == WBFS_DEVICE_SDHC) {
|
||||
if (sdhc_mode_sd == 0) {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
} else {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
}
|
||||
if (!ret) {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
fs_ntfs_mount = 1;
|
||||
fs_ntfs_sec = sector; //_FAT_startSector;
|
||||
|
||||
return 0;
|
||||
fs_ntfs_mount = 1;
|
||||
fs_ntfs_sec = sector; //_FAT_startSector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 UnmountNTFS(void) {
|
||||
/* Unmount device */
|
||||
ntfsUnmount("NTFS:/", true);
|
||||
s32 UnmountNTFS(void)
|
||||
{
|
||||
/* Unmount device */
|
||||
ntfsUnmount("NTFS:/", true);
|
||||
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _FAT_mem_init() {
|
||||
void _FAT_mem_init()
|
||||
{
|
||||
}
|
||||
|
||||
void* _FAT_mem_allocate(size_t size) {
|
||||
return malloc(size);
|
||||
void* _FAT_mem_allocate(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void* _FAT_mem_align(size_t size) {
|
||||
return memalign(32, size);
|
||||
void* _FAT_mem_align(size_t size)
|
||||
{
|
||||
return memalign(32, size);
|
||||
}
|
||||
|
||||
void _FAT_mem_free(void *mem) {
|
||||
free(mem);
|
||||
void _FAT_mem_free(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
void* ntfs_alloc (size_t size) {
|
||||
return _FAT_mem_allocate(size);
|
||||
void* ntfs_alloc (size_t size)
|
||||
{
|
||||
return _FAT_mem_allocate(size);
|
||||
}
|
||||
|
||||
void* ntfs_align (size_t size) {
|
||||
return _FAT_mem_align(size);
|
||||
void* ntfs_align (size_t size)
|
||||
{
|
||||
return _FAT_mem_align(size);
|
||||
}
|
||||
|
||||
void ntfs_free (void* mem) {
|
||||
_FAT_mem_free(mem);
|
||||
void ntfs_free (void* mem)
|
||||
{
|
||||
_FAT_mem_free(mem);
|
||||
}
|
||||
|
@ -5,12 +5,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int fat_sd_mount;
|
||||
extern sec_t fat_sd_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fat_sd_mount;
|
||||
extern sec_t fat_sd_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
|
||||
int USBDevice_Init();
|
||||
void USBDevice_deInit();
|
||||
@ -19,16 +19,16 @@ extern "C" {
|
||||
int isInserted(const char *path);
|
||||
int SDCard_Init();
|
||||
void SDCard_deInit();
|
||||
|
||||
s32 MountNTFS(u32 sector);
|
||||
s32 UnmountNTFS(void);
|
||||
|
||||
s32 MountNTFS(u32 sector);
|
||||
s32 UnmountNTFS(void);
|
||||
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fs_ntfs_mount;
|
||||
extern sec_t fs_ntfs_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fs_ntfs_mount;
|
||||
extern sec_t fs_ntfs_sec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -10,27 +10,31 @@ bool textVideoInit = false;
|
||||
#include <stdarg.h>
|
||||
|
||||
//using the gprintf from crediar because it is smaller than mine
|
||||
void gprintf( const char *str, ... ) {
|
||||
if (!(geckoinit))return;
|
||||
void gprintf( const char *str, ... )
|
||||
{
|
||||
if (!(geckoinit))return;
|
||||
|
||||
char astr[4096];
|
||||
char astr[4096];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,str);
|
||||
va_list ap;
|
||||
va_start(ap,str);
|
||||
|
||||
vsprintf( astr, str, ap );
|
||||
vsprintf( astr, str, ap );
|
||||
|
||||
va_end(ap);
|
||||
va_end(ap);
|
||||
|
||||
usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
||||
}
|
||||
usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
||||
}
|
||||
|
||||
bool InitGecko() {
|
||||
u32 geckoattached = usb_isgeckoalive(EXI_CHANNEL_1);
|
||||
if (geckoattached) {
|
||||
usb_flush(EXI_CHANNEL_1);
|
||||
return true;
|
||||
} else return false;
|
||||
bool InitGecko()
|
||||
{
|
||||
u32 geckoattached = usb_isgeckoalive(EXI_CHANNEL_1);
|
||||
if (geckoattached)
|
||||
{
|
||||
usb_flush(EXI_CHANNEL_1);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,12 +8,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef NO_DEBUG
|
||||
//use this just like printf();
|
||||
void gprintf(const char *str, ...);
|
||||
bool InitGecko();
|
||||
//use this just like printf();
|
||||
void gprintf(const char *str, ...);
|
||||
bool InitGecko();
|
||||
#else
|
||||
#define gprintf(...)
|
||||
#define InitGecko() false
|
||||
#define gprintf(...)
|
||||
#define InitGecko() false
|
||||
#endif /* NO_DEBUG */
|
||||
|
||||
|
||||
|
@ -37,9 +37,9 @@ void CopyHomebrewMemory(u32 read, u8 *temp, u32 len) {
|
||||
}
|
||||
|
||||
int BootHomebrew(char * path) {
|
||||
loadStub();
|
||||
if (Set_Stub_Split(0x00010001,"UNEO")<0)
|
||||
Set_Stub_Split(0x00010001,"ULNR");
|
||||
loadStub();
|
||||
if (Set_Stub_Split(0x00010001,"UNEO")<0)
|
||||
Set_Stub_Split(0x00010001,"ULNR");
|
||||
void *buffer = NULL;
|
||||
u32 filesize = 0;
|
||||
entrypoint entry;
|
||||
@ -106,9 +106,9 @@ int BootHomebrew(char * path) {
|
||||
}
|
||||
|
||||
int BootHomebrewFromMem() {
|
||||
loadStub();
|
||||
if (Set_Stub_Split(0x00010001,"UNEO")<0)
|
||||
Set_Stub_Split(0x00010001,"ULNR");
|
||||
loadStub();
|
||||
if (Set_Stub_Split(0x00010001,"UNEO")<0)
|
||||
Set_Stub_Split(0x00010001,"ULNR");
|
||||
entrypoint entry;
|
||||
u32 cpu_isr;
|
||||
|
||||
|
@ -86,9 +86,9 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
/*** Sound Variables ***/
|
||||
GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume);
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if (!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
GuiSound btnClick1(button_click_pcm, button_click_pcm_size, Settings.sfxvolume);
|
||||
|
||||
/*** Image Variables ***/
|
||||
@ -219,11 +219,11 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
GuiImage MainButton2Img(&MainButtonImgData);
|
||||
GuiImage MainButton2ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton2Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton2Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255 });
|
||||
MainButton2Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton2Txt.SetPosition(148, -12);
|
||||
MainButton2Txt.SetMaxWidth(MainButton2Img.GetWidth()-150, GuiText::DOTTED);
|
||||
GuiText MainButton2DescTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton2DescTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255});
|
||||
MainButton2DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton2DescTxt.SetPosition(148, 15);
|
||||
MainButton2DescTxt.SetMaxWidth(MainButton2Img.GetWidth()-150, GuiText::DOTTED);
|
||||
@ -250,11 +250,11 @@ int MenuHomebrewBrowse() {
|
||||
MainButton3Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3Txt.SetPosition(148, -12);
|
||||
MainButton3Txt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::DOTTED);
|
||||
GuiText MainButton3DescTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton3DescTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255});
|
||||
MainButton3DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3DescTxt.SetPosition(148, 15);
|
||||
MainButton3DescTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::DOTTED);
|
||||
GuiText MainButton3DescOverTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton3DescOverTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255 });
|
||||
MainButton3DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3DescOverTxt.SetPosition(148, 15);
|
||||
MainButton3DescOverTxt.SetMaxWidth(MainButton3Img.GetWidth()-150, GuiText::SCROLL);
|
||||
@ -273,7 +273,7 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
GuiImage MainButton4Img(&MainButtonImgData);
|
||||
GuiImage MainButton4ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton4Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton4Txt(MainButtonText, 18, (GXColor) {0, 0, 0, 255} );
|
||||
MainButton4Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4Txt.SetPosition(148, -12);
|
||||
MainButton4Txt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::DOTTED);
|
||||
@ -281,7 +281,7 @@ int MenuHomebrewBrowse() {
|
||||
MainButton4DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4DescTxt.SetPosition(148, 15);
|
||||
MainButton4DescTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::DOTTED);
|
||||
GuiText MainButton4DescOverTxt(MainButtonText, 18, (GXColor) {0, 0, 0, 255});
|
||||
GuiText MainButton4DescOverTxt(MainButtonText, 18, (GXColor) { 0, 0, 0, 255});
|
||||
MainButton4DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4DescOverTxt.SetPosition(148, 15);
|
||||
MainButton4DescOverTxt.SetMaxWidth(MainButton4Img.GetWidth()-150, GuiText::SCROLL);
|
||||
@ -808,8 +808,8 @@ int MenuHomebrewBrowse() {
|
||||
int len = NETWORKBLOCKSIZE;
|
||||
temp = (u8 *) malloc(infilesize);
|
||||
|
||||
bool error = false;
|
||||
u8 *ptr = temp;
|
||||
bool error = false;
|
||||
u8 *ptr = temp;
|
||||
while (read < infilesize) {
|
||||
|
||||
ShowProgress(tr("Receiving file from:"), GetIncommingIP(), NULL, read, infilesize, true);
|
||||
@ -823,73 +823,74 @@ int MenuHomebrewBrowse() {
|
||||
|
||||
if (result < 0) {
|
||||
WindowPrompt(tr("Error while transfering data."), 0, tr("OK"));
|
||||
error = true;
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptr += result;
|
||||
ptr += result;
|
||||
|
||||
read += result;
|
||||
}
|
||||
|
||||
char filename[101];
|
||||
if (!error) {
|
||||
|
||||
network_read((u8*) &filename, 100);
|
||||
|
||||
// Do we need to unzip this thing?
|
||||
if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4) {
|
||||
|
||||
char filename[101];
|
||||
if (!error) {
|
||||
|
||||
network_read((u8*) &filename, 100);
|
||||
|
||||
// Do we need to unzip this thing?
|
||||
if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4) {
|
||||
|
||||
// We need to unzip...
|
||||
if (temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04) {
|
||||
// It's a zip file, unzip to the apps directory
|
||||
|
||||
// Zip archive, ask for permission to install the zip
|
||||
char zippath[255];
|
||||
sprintf((char *) &zippath, "%s%s", Settings.homebrewapps_path, filename);
|
||||
|
||||
FILE *fp = fopen(zippath, "wb");
|
||||
if (fp != NULL) {
|
||||
fwrite(temp, 1, infilesize, fp);
|
||||
fclose(fp);
|
||||
|
||||
// Now unzip the zip file...
|
||||
unzFile uf = unzOpen(zippath);
|
||||
if (uf==NULL) {
|
||||
error = true;
|
||||
} else {
|
||||
extractZip(uf,0,1,0, Settings.homebrewapps_path);
|
||||
unzCloseCurrentFile(uf);
|
||||
|
||||
remove(zippath);
|
||||
|
||||
// Reload this menu here...
|
||||
menu = MENU_HOMEBREWBROWSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
}
|
||||
} else if (uncfilesize != 0) { // if uncfilesize == 0, it's not compressed
|
||||
// It's compressed, uncompress
|
||||
u8 *unc = (u8 *) malloc(uncfilesize);
|
||||
uLongf f = uncfilesize;
|
||||
error = uncompress(unc, &f, temp, infilesize) != Z_OK;
|
||||
uncfilesize = f;
|
||||
|
||||
free(temp);
|
||||
temp = unc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error && strstr(filename,".zip") == NULL) {
|
||||
innetbuffer = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// We need to unzip...
|
||||
if (temp[0] == 'P' && temp[1] == 'K' && temp[2] == 0x03 && temp[3] == 0x04) {
|
||||
// It's a zip file, unzip to the apps directory
|
||||
|
||||
// Zip archive, ask for permission to install the zip
|
||||
char zippath[255];
|
||||
sprintf((char *) &zippath, "%s%s", Settings.homebrewapps_path, filename);
|
||||
|
||||
FILE *fp = fopen(zippath, "wb");
|
||||
if (fp != NULL)
|
||||
{
|
||||
fwrite(temp, 1, infilesize, fp);
|
||||
fclose(fp);
|
||||
|
||||
// Now unzip the zip file...
|
||||
unzFile uf = unzOpen(zippath);
|
||||
if (uf==NULL) {
|
||||
error = true;
|
||||
} else {
|
||||
extractZip(uf,0,1,0, Settings.homebrewapps_path);
|
||||
unzCloseCurrentFile(uf);
|
||||
|
||||
remove(zippath);
|
||||
|
||||
// Reload this menu here...
|
||||
menu = MENU_HOMEBREWBROWSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
}
|
||||
} else if (uncfilesize != 0) { // if uncfilesize == 0, it's not compressed
|
||||
// It's compressed, uncompress
|
||||
u8 *unc = (u8 *) malloc(uncfilesize);
|
||||
uLongf f = uncfilesize;
|
||||
error = uncompress(unc, &f, temp, infilesize) != Z_OK;
|
||||
uncfilesize = f;
|
||||
|
||||
free(temp);
|
||||
temp = unc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error && strstr(filename,".zip") == NULL) {
|
||||
innetbuffer = temp;
|
||||
}
|
||||
}
|
||||
|
||||
ProgressStop();
|
||||
|
||||
if (error || read != infilesize) {
|
||||
@ -897,18 +898,18 @@ int MenuHomebrewBrowse() {
|
||||
FreeHomebrewBuffer();
|
||||
} else {
|
||||
if (strstr(filename,".dol") || strstr(filename,".DOL")
|
||||
|| strstr(filename,".elf") || strstr(filename,".ELF")) {
|
||||
|| strstr(filename,".elf") || strstr(filename,".ELF")) {
|
||||
boothomebrew = 2;
|
||||
menu = MENU_EXIT;
|
||||
CloseConnection();
|
||||
break;
|
||||
} else if (strstr(filename,".zip")) {
|
||||
WindowPrompt(tr("Success:"), tr("Uploaded ZIP file installed to homebrew directory."), tr("OK"));
|
||||
CloseConnection();
|
||||
CloseConnection();
|
||||
} else {
|
||||
FreeHomebrewBuffer();
|
||||
WindowPrompt(tr("ERROR:"), tr("Not a DOL/ELF file."), tr("OK"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 891 B After Width: | Height: | Size: 856 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 937 B |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 211 B After Width: | Height: | Size: 118 B |
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 147 B After Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 152 B After Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 86 B |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.5 KiB |