2009-11-10 00:03:13 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ogcsys.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <new>
|
|
|
|
|
|
|
|
#include "usbloader/disc.h"
|
|
|
|
#include "usbloader/wbfs.h"
|
|
|
|
#include "prompts/PromptWindows.h"
|
|
|
|
#include "libwbfs/libwbfs.h"
|
|
|
|
#include "language/gettext.h"
|
|
|
|
#include "bannersound.h"
|
|
|
|
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
struct IMD5Header
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
u32 fcc;
|
|
|
|
u32 filesize;
|
|
|
|
u8 zeroes[8];
|
|
|
|
u8 crypto[16];
|
|
|
|
} __attribute__( ( packed ) );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
struct IMETHeader
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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 ) );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
struct U8Header
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
u32 fcc;
|
|
|
|
u32 rootNodeOffset;
|
|
|
|
u32 headerSize;
|
|
|
|
u32 dataOffset;
|
|
|
|
u8 zeroes[16];
|
|
|
|
} __attribute__( ( packed ) );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
struct U8Entry
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 fileType : 8;
|
|
|
|
u32 nameOffset : 24;
|
|
|
|
};
|
|
|
|
u32 fileOffset;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 fileLength;
|
|
|
|
u32 numEntries;
|
|
|
|
};
|
|
|
|
} __attribute__( ( packed ) );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
struct LZ77Info
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
u16 length : 4;
|
|
|
|
u16 offset : 12;
|
|
|
|
} __attribute__( ( packed ) );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
static char *u8Filename( const U8Entry *fst, int i )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
return ( char * )( fst + fst[0].numEntries ) + fst[i].nameOffset;
|
2009-11-10 00:03:13 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
inline u32 le32( u32 i )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
return ( ( i & 0xFF ) << 24 ) | ( ( i & 0xFF00 ) << 8 ) | ( ( i & 0xFF0000 ) >> 8 ) | ( ( i & 0xFF000000 ) >> 24 );
|
2009-11-10 00:03:13 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
inline u16 le16( u16 i )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
return ( ( i & 0xFF ) << 8 ) | ( ( i & 0xFF00 ) >> 8 );
|
2009-11-10 00:03:13 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
static u8 *uncompressLZ77( const u8 *inBuf, u32 inLength, u32 &size )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2009-11-10 00:03:13 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
const u8 *LoadBannerSound( const u8 *discid, u32 *size )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
if ( !discid )
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
Disc_SetUSB( NULL );
|
|
|
|
wbfs_disc_t *disc = WBFS_OpenDisc( ( u8 * ) discid );
|
|
|
|
if ( !disc )
|
|
|
|
{
|
|
|
|
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
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"));
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
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"));
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
wd_close_disc( wdisc );
|
|
|
|
WBFS_CloseDisc( disc );
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
const U8Entry *fst;
|
2009-11-10 00:03:13 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
const IMETHeader *imetHdr = ( IMETHeader * )opening_bnr;
|
|
|
|
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
|
|
|
{
|
|
|
|
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
|
|
|
free( opening_bnr );
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
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 );
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
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 );
|
2009-11-10 00:03:13 +01:00
|
|
|
return NULL;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
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;
|
2009-11-10 00:03:13 +01:00
|
|
|
}
|