mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-11-29 16:14:19 +01:00
* add whatever local changes i have in the lz77 & u8 classes
* make everything build again git-svn-id: http://wiiqt.googlecode.com/svn/trunk@116 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
parent
a4648d8cac
commit
54fb86682a
467
WiiQt/lz77.cpp
467
WiiQt/lz77.cpp
@ -18,6 +18,59 @@ int LZ77::GetLz77Offset( const QByteArray &data )
|
|||||||
return start.indexOf( "LZ77" );
|
return start.indexOf( "LZ77" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LZ77::CompressionType LZ77::GetCompressedType( const QByteArray &data, int *outOffset )
|
||||||
|
{
|
||||||
|
if( data.startsWith( 0x10 ) )
|
||||||
|
{
|
||||||
|
if( outOffset )
|
||||||
|
{
|
||||||
|
*outOffset = 0;
|
||||||
|
}
|
||||||
|
return v10;
|
||||||
|
}
|
||||||
|
if( data.startsWith( 0x11 ) )
|
||||||
|
{
|
||||||
|
if( outOffset )
|
||||||
|
{
|
||||||
|
*outOffset = 0;
|
||||||
|
}
|
||||||
|
return v11;
|
||||||
|
}
|
||||||
|
int t = GetLz77Offset( data );
|
||||||
|
if( t >= 0 )
|
||||||
|
{
|
||||||
|
if( outOffset )
|
||||||
|
{
|
||||||
|
*outOffset = t;
|
||||||
|
}
|
||||||
|
return v10_w_magic;
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LZ77::Decompress( const QByteArray &stuff, LZ77::CompressionType *outType )
|
||||||
|
{
|
||||||
|
int off;
|
||||||
|
CompressionType t = GetCompressedType( stuff, &off );
|
||||||
|
if( outType )
|
||||||
|
{
|
||||||
|
*outType = t;
|
||||||
|
}
|
||||||
|
if( t == v10 )
|
||||||
|
{
|
||||||
|
return Decompress_v10( stuff, 0 );
|
||||||
|
}
|
||||||
|
if( t == v10_w_magic )
|
||||||
|
{
|
||||||
|
return Decompress_v10( stuff, off + 4 );
|
||||||
|
}
|
||||||
|
if( t == v11 )
|
||||||
|
{
|
||||||
|
return LZ77_11::Decompress( stuff );
|
||||||
|
}
|
||||||
|
return stuff;
|
||||||
|
}
|
||||||
|
|
||||||
void LZ77::InitTree()
|
void LZ77::InitTree()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -136,12 +189,16 @@ void LZ77::InsertNode( int r )
|
|||||||
|
|
||||||
quint32 LZ77::GetDecompressedSize( const QByteArray &data )
|
quint32 LZ77::GetDecompressedSize( const QByteArray &data )
|
||||||
{
|
{
|
||||||
int off = GetLz77Offset( data );
|
int off;
|
||||||
if( off == -1 )
|
LZ77::CompressionType ct = LZ77::GetCompressedType( data, &off );
|
||||||
{
|
if( ct == None )
|
||||||
qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic";
|
{
|
||||||
return 0;
|
return data.size();
|
||||||
}
|
}
|
||||||
|
if( ct == v10_w_magic )
|
||||||
|
{
|
||||||
|
off += 4;
|
||||||
|
}
|
||||||
QByteArray ba = data;
|
QByteArray ba = data;
|
||||||
QBuffer buf( &ba );
|
QBuffer buf( &ba );
|
||||||
if( !buf.open( QBuffer::ReadOnly ) )
|
if( !buf.open( QBuffer::ReadOnly ) )
|
||||||
@ -149,16 +206,21 @@ quint32 LZ77::GetDecompressedSize( const QByteArray &data )
|
|||||||
qWarning() << "LZ77::GetDecompressedSize -> Can't create buffer";
|
qWarning() << "LZ77::GetDecompressedSize -> Can't create buffer";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
buf.seek( off + 4 );
|
buf.seek( off );
|
||||||
|
|
||||||
quint32 gbaheader;
|
quint32 gbaheader;
|
||||||
buf.seek( off + 4 );
|
buf.seek( off );
|
||||||
buf.read( (char*)&gbaheader, 4 );
|
buf.read( (char*)&gbaheader, 4 );
|
||||||
|
quint32 ret = ( gbaheader >> 8 );
|
||||||
|
if( !ret )
|
||||||
|
{
|
||||||
|
buf.read( (char*)&ret, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
return ( gbaheader >> 8 );
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
QByteArray LZ77::Decompress_v10( const QByteArray &compressed, int offset )
|
||||||
{
|
{
|
||||||
int N = 4096;
|
int N = 4096;
|
||||||
int F = 18;
|
int F = 18;
|
||||||
@ -185,7 +247,7 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
|||||||
}
|
}
|
||||||
|
|
||||||
quint32 gbaheader;
|
quint32 gbaheader;
|
||||||
infile.seek( offset + 4 );
|
infile.seek( offset );
|
||||||
infile.read( (char*)&gbaheader, 4 );
|
infile.read( (char*)&gbaheader, 4 );
|
||||||
|
|
||||||
decomp_size = gbaheader >> 8;
|
decomp_size = gbaheader >> 8;
|
||||||
@ -255,7 +317,7 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LZ77::Decompress( const QByteArray &compressed )
|
/*QByteArray LZ77::Decompress( const QByteArray &compressed )
|
||||||
{
|
{
|
||||||
int off = GetLz77Offset( compressed );
|
int off = GetLz77Offset( compressed );
|
||||||
if( off < 0 )
|
if( off < 0 )
|
||||||
@ -264,18 +326,33 @@ QByteArray LZ77::Decompress( const QByteArray &compressed )
|
|||||||
return compressed;
|
return compressed;
|
||||||
}
|
}
|
||||||
return Decompress( compressed, off );
|
return Decompress( compressed, off );
|
||||||
|
}*/
|
||||||
|
|
||||||
|
QByteArray LZ77::Compress( const QByteArray &ba, LZ77::CompressionType type )
|
||||||
|
{
|
||||||
|
if( type == v10 )
|
||||||
|
{
|
||||||
|
return Compress_v10( ba, false );
|
||||||
|
}
|
||||||
|
if( type == v10_w_magic )
|
||||||
|
{
|
||||||
|
return Compress_v10( ba, true );
|
||||||
|
}
|
||||||
|
if( type == v11 )
|
||||||
|
{
|
||||||
|
return LZ77_11::Compress( ba );
|
||||||
|
}
|
||||||
|
return ba;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LZ77::Compress( const QByteArray &ba )
|
QByteArray LZ77::Compress_v10( const QByteArray &ba, bool addMagic )
|
||||||
{
|
{
|
||||||
//testing 1, 2
|
|
||||||
//return ba;
|
|
||||||
LZ77 lz;
|
LZ77 lz;
|
||||||
QByteArray ret = lz.Compr( ba );
|
QByteArray ret = lz.Compr_v10( ba, addMagic );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LZ77::Compr( const QByteArray &ba )
|
QByteArray LZ77::Compr_v10( const QByteArray &ba, bool addMagic )
|
||||||
{
|
{
|
||||||
int i, len, r, s, last_match_length, code_buf_ptr;
|
int i, len, r, s, last_match_length, code_buf_ptr;
|
||||||
char ch;
|
char ch;
|
||||||
@ -284,7 +361,7 @@ QByteArray LZ77::Compr( const QByteArray &ba )
|
|||||||
int N = 4096;
|
int N = 4096;
|
||||||
int F = 18;
|
int F = 18;
|
||||||
int threshold = 2;
|
int threshold = 2;
|
||||||
quint32 filesize = (ba.size() << 8) + 0x10;
|
quint32 filesize;
|
||||||
|
|
||||||
QByteArray crap = ba;
|
QByteArray crap = ba;
|
||||||
QBuffer infile( &crap );
|
QBuffer infile( &crap );
|
||||||
@ -300,12 +377,31 @@ QByteArray LZ77::Compr( const QByteArray &ba )
|
|||||||
qWarning() << "Can't create buffer 2";
|
qWarning() << "Can't create buffer 2";
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
output.putChar( 'L' );
|
|
||||||
output.putChar( 'Z' );
|
|
||||||
output.putChar( '7' );
|
|
||||||
output.putChar( '7' );
|
|
||||||
|
|
||||||
output.write( (const char*)&filesize, 4 );
|
if( addMagic )
|
||||||
|
{
|
||||||
|
output.putChar( 'L' );
|
||||||
|
output.putChar( 'Z' );
|
||||||
|
output.putChar( '7' );
|
||||||
|
output.putChar( '7' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ba.size() <= 0xffffff )
|
||||||
|
{
|
||||||
|
filesize = ( ba.size() << 8 ) | 0x10;
|
||||||
|
output.write( (const char*)&filesize, 4 );
|
||||||
|
//output.putChar( '\0' );
|
||||||
|
//output.putChar( '\0' );
|
||||||
|
//output.putChar( '\0' );
|
||||||
|
//output.putChar( '\0' );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filesize = 0x10;
|
||||||
|
output.write( (const char*)&filesize, 4 );
|
||||||
|
filesize = ba.size();
|
||||||
|
output.write( (const char*)&filesize, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
InitTree();
|
InitTree();
|
||||||
code_buf[ 0 ] = 0;
|
code_buf[ 0 ] = 0;
|
||||||
@ -396,3 +492,328 @@ QByteArray LZ77::Compr( const QByteArray &ba )
|
|||||||
infile.close();
|
infile.close();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LZ77_11::LZ77_11()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LZ77_11::Compress( const QByteArray &stuff )
|
||||||
|
{
|
||||||
|
// Test if the file is too large to be compressed
|
||||||
|
if( (quint64)stuff.size() > 0xFFFFFFFF )
|
||||||
|
{
|
||||||
|
qDebug() << "LZ77_11::Compress -> Input file is too large to compress.";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 decompressedSize = stuff.size();
|
||||||
|
|
||||||
|
quint32 SourcePointer = 0x0;
|
||||||
|
quint32 DestPointer = 0x4;
|
||||||
|
|
||||||
|
quint32 tmp;
|
||||||
|
QByteArray ret( decompressedSize, '\0' );//will reduce the size later
|
||||||
|
QBuffer buf( &ret );
|
||||||
|
buf.open( QIODevice::WriteOnly );
|
||||||
|
|
||||||
|
|
||||||
|
// Set up the Lz Compression Dictionary
|
||||||
|
LzWindowDictionary LzDictionary;
|
||||||
|
LzDictionary.SetWindowSize( 0x1000 );
|
||||||
|
LzDictionary.SetMaxMatchAmount( 0xFFFF + 273 );
|
||||||
|
|
||||||
|
// Figure out where we are going to write the decompressed file size
|
||||||
|
if( stuff.size() <= 0xFFFFFF )
|
||||||
|
{
|
||||||
|
tmp = ( decompressedSize << 8 ) | 0x11; //dont switch endian?
|
||||||
|
buf.write( (const char*)&tmp, 4 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmp = 0x11;
|
||||||
|
buf.write( (const char*)&tmp, 4 ); //dont switch endian?
|
||||||
|
tmp = decompressedSize;
|
||||||
|
buf.write( (const char*)&tmp, 4 ); //dont switch endian?
|
||||||
|
DestPointer += 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start compression
|
||||||
|
while( SourcePointer < decompressedSize )
|
||||||
|
{
|
||||||
|
quint8 Flag = 0x0;
|
||||||
|
quint32 FlagPosition = DestPointer;
|
||||||
|
// It will be filled in later
|
||||||
|
buf.putChar( Flag );
|
||||||
|
DestPointer++;
|
||||||
|
|
||||||
|
for( int i = 7; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
QList<int>LzSearchMatch = LzDictionary.Search( stuff, SourcePointer, decompressedSize );
|
||||||
|
if( LzSearchMatch[ 1 ] > 0 ) // There is a compression match
|
||||||
|
{
|
||||||
|
Flag |= (quint8)( 1 << i );
|
||||||
|
|
||||||
|
// Write the distance/length pair
|
||||||
|
if( LzSearchMatch[ 1 ] <= 0xF + 1 ) // 2 bytes
|
||||||
|
{
|
||||||
|
buf.putChar( (quint8)( ( ( ( LzSearchMatch[ 1 ] - 1) & 0xF ) << 4 ) | ( ( ( LzSearchMatch[ 0 ] - 1 ) & 0xFFF ) >> 8 ) ) );
|
||||||
|
buf.putChar( (quint8)( ( LzSearchMatch[ 0 ] - 1 ) & 0xFF ) );
|
||||||
|
DestPointer += 2;
|
||||||
|
}
|
||||||
|
else if (LzSearchMatch[1] <= 0xFF + 17) // 3 bytes
|
||||||
|
{
|
||||||
|
buf.putChar( (quint8)(((LzSearchMatch[1] - 17) & 0xFF) >> 4) );
|
||||||
|
buf.putChar( (quint8)((((LzSearchMatch[1] - 17) & 0xF) << 4) | (((LzSearchMatch[0] - 1) & 0xFFF) >> 8)) );
|
||||||
|
buf.putChar( (quint8)((LzSearchMatch[0] - 1) & 0xFF) );
|
||||||
|
DestPointer += 3;
|
||||||
|
}
|
||||||
|
else // 4 bytes
|
||||||
|
{
|
||||||
|
buf.putChar( (quint8)((1 << 4) | (((LzSearchMatch[1] - 273) & 0xFFFF) >> 12)) );
|
||||||
|
buf.putChar( (quint8)(((LzSearchMatch[1] - 273) & 0xFFF) >> 4) );
|
||||||
|
buf.putChar( (quint8)((((LzSearchMatch[1] - 273) & 0xF) << 4) | (((LzSearchMatch[0] - 1) & 0xFFF) >> 8)) );
|
||||||
|
buf.putChar( (quint8)((LzSearchMatch[0] - 1) & 0xFF) );
|
||||||
|
DestPointer += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
LzDictionary.AddEntryRange( stuff, (int)SourcePointer, LzSearchMatch[ 1 ] );
|
||||||
|
LzDictionary.SlideWindow( LzSearchMatch[ 1 ] );
|
||||||
|
|
||||||
|
SourcePointer += (quint32)LzSearchMatch[ 1 ];
|
||||||
|
}
|
||||||
|
else // There wasn't a match
|
||||||
|
{
|
||||||
|
Flag |= (quint8)(0 << i);
|
||||||
|
|
||||||
|
buf.putChar( stuff.at( SourcePointer ) );
|
||||||
|
|
||||||
|
LzDictionary.AddEntry( stuff, (int)SourcePointer );
|
||||||
|
LzDictionary.SlideWindow( 1 );
|
||||||
|
|
||||||
|
SourcePointer++;
|
||||||
|
DestPointer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for out of bounds
|
||||||
|
if( SourcePointer >= decompressedSize )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the flag.
|
||||||
|
// Note that the original position gets reset after writing.
|
||||||
|
buf.seek( FlagPosition );
|
||||||
|
buf.putChar( Flag );
|
||||||
|
buf.seek( DestPointer );
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.close();
|
||||||
|
ret.resize( DestPointer );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LZ77_11::Decompress( QByteArray stuff )
|
||||||
|
{
|
||||||
|
if( !stuff.startsWith( 0x11 ) )
|
||||||
|
{
|
||||||
|
qWarning() << "LZ77_11::Decompress -> data doesnt start with 0x11";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compressed & Decompressed Data Information
|
||||||
|
QBuffer b( &stuff );
|
||||||
|
b.open( QIODevice::ReadOnly );
|
||||||
|
|
||||||
|
quint32 compressedSize = (quint32)stuff.size();
|
||||||
|
quint32 decompressedSize;
|
||||||
|
b.read( (char*)&decompressedSize, 4 ); //is this really little endian?
|
||||||
|
decompressedSize >>= 8;
|
||||||
|
|
||||||
|
quint32 sourcePointer = 0x4;
|
||||||
|
quint32 destPointer = 0x0;
|
||||||
|
unsigned char tempbuffer[ 10 ];
|
||||||
|
quint32 backwards_offset;
|
||||||
|
|
||||||
|
if( !decompressedSize ) // Next 4 bytes are the decompressed size
|
||||||
|
{
|
||||||
|
b.read( (char*)&decompressedSize, 4 );
|
||||||
|
sourcePointer += 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.close();
|
||||||
|
|
||||||
|
QByteArray decompressedData( decompressedSize, '\0' );
|
||||||
|
if( (quint32)decompressedData.size() != decompressedSize )
|
||||||
|
{
|
||||||
|
qWarning() << "LZ77_11::Decompress -> failed to allocate" << hex << decompressedSize << "bytes";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Decompression
|
||||||
|
quint32 num_bytes_to_copy;
|
||||||
|
quint32 copy_start_index;
|
||||||
|
while( sourcePointer < compressedSize && destPointer < decompressedSize )
|
||||||
|
{
|
||||||
|
quint8 flag = stuff[ sourcePointer++ ];
|
||||||
|
|
||||||
|
|
||||||
|
for( quint32 i = 0; i < 8; i++ )
|
||||||
|
{
|
||||||
|
if( flag & ( 0x80 >> i ) )
|
||||||
|
{
|
||||||
|
// Take encoded data
|
||||||
|
tempbuffer[ 0 ] = stuff[ sourcePointer++ ];
|
||||||
|
tempbuffer[ 1 ] = stuff[ sourcePointer++ ];
|
||||||
|
|
||||||
|
switch( tempbuffer[ 0 ] & 0xF0 )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
tempbuffer[ 2 ] = stuff[ sourcePointer++ ];
|
||||||
|
num_bytes_to_copy = ( ( tempbuffer[ 0 ] << 4 ) + ( tempbuffer[ 1 ] >> 4 ) + 0x11 );
|
||||||
|
backwards_offset = ( ( ( tempbuffer[ 1 ] & 0x0F ) << 8 ) + tempbuffer[ 2 ] + 1 );
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
tempbuffer[ 2 ] = stuff[ sourcePointer++ ];
|
||||||
|
tempbuffer[ 3 ] = stuff[ sourcePointer++ ];
|
||||||
|
num_bytes_to_copy = ( ( tempbuffer[ 0 ] & 0x0F ) << 12 ) + ( tempbuffer[ 1 ] << 4 ) + ( tempbuffer[ 2 ] >> 4 ) + 0x111;
|
||||||
|
backwards_offset = ( ( tempbuffer[ 2 ] & 0x0F ) << 8 ) + tempbuffer[ 3 ] + 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
num_bytes_to_copy = ( tempbuffer[ 0 ] >> 4 ) + 0x01;
|
||||||
|
backwards_offset = ( ( tempbuffer[ 0 ] & 0x0F ) << 8 ) + tempbuffer[ 1 ] + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
copy_start_index = destPointer - backwards_offset;
|
||||||
|
for( quint32 copy_counter = 0; copy_counter < num_bytes_to_copy; copy_counter++ )
|
||||||
|
{
|
||||||
|
if( ( copy_start_index + copy_counter ) >= destPointer )
|
||||||
|
{
|
||||||
|
qWarning() << "LZ77_11::Decompress -> Error occured while decompressing: The input seems to be telling us to copy uninitialized data.";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decompressedData[ destPointer++ ] = decompressedData[ copy_start_index + copy_counter ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decompressedData[ destPointer++ ] = stuff[ sourcePointer++ ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decompressedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
LzWindowDictionary::LzWindowDictionary()
|
||||||
|
{
|
||||||
|
WindowSize = 0x1000;
|
||||||
|
WindowStart = 0;
|
||||||
|
WindowLength = 0;
|
||||||
|
MinMatchAmount = 3;
|
||||||
|
MaxMatchAmount = 18;
|
||||||
|
BlockSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> LzWindowDictionary::Search( const QByteArray &DecompressedData, quint32 offset, quint32 length )
|
||||||
|
{
|
||||||
|
RemoveOldEntries( DecompressedData[ offset ] ); // Remove old entries for this index
|
||||||
|
|
||||||
|
if( offset < (quint32)MinMatchAmount || length - offset < (quint32)MinMatchAmount ) // Can't find matches if there isn't enough data
|
||||||
|
return QList<int>() << 0 << 0;
|
||||||
|
|
||||||
|
QList<int>Match = QList<int>() << 0 << 0;
|
||||||
|
int MatchStart;
|
||||||
|
int MatchSize;
|
||||||
|
|
||||||
|
for( int i = OffsetList[ (quint8)( DecompressedData[ offset ] ) ].size() - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
MatchStart = OffsetList[ (quint8)( DecompressedData[ offset ] ) ][ i ];
|
||||||
|
MatchSize = 1;
|
||||||
|
|
||||||
|
while( MatchSize < MaxMatchAmount
|
||||||
|
&& MatchSize < WindowLength
|
||||||
|
&& (quint32)(MatchStart + MatchSize) < offset
|
||||||
|
&& offset + MatchSize < length
|
||||||
|
&& DecompressedData[ offset + MatchSize ] == DecompressedData[ MatchStart + MatchSize ] )
|
||||||
|
MatchSize++;
|
||||||
|
|
||||||
|
if( MatchSize >= MinMatchAmount && MatchSize > Match[ 1 ] ) // This is a good match
|
||||||
|
{
|
||||||
|
Match = QList<int>() << (int)(offset - MatchStart) << MatchSize;
|
||||||
|
|
||||||
|
if( MatchSize == MaxMatchAmount ) // Don't look for more matches
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the match.
|
||||||
|
// If no match was made, the distance & length pair will be zero
|
||||||
|
return Match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slide the window
|
||||||
|
void LzWindowDictionary::SlideWindow( int Amount )
|
||||||
|
{
|
||||||
|
if( WindowLength == WindowSize )
|
||||||
|
WindowStart += Amount;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( WindowLength + Amount <= WindowSize )
|
||||||
|
WindowLength += Amount;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Amount -= ( WindowSize - WindowLength );
|
||||||
|
WindowLength = WindowSize;
|
||||||
|
WindowStart += Amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slide the window to the next block
|
||||||
|
void LzWindowDictionary::SlideBlock()
|
||||||
|
{
|
||||||
|
WindowStart += BlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old entries
|
||||||
|
void LzWindowDictionary::RemoveOldEntries( quint8 index )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < OffsetList[ index ].size(); ) // Don't increment i
|
||||||
|
{
|
||||||
|
if( OffsetList[ index ][ i ] >= WindowStart )
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
OffsetList[ index ].removeAt( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set variables
|
||||||
|
void LzWindowDictionary::SetWindowSize( int size )
|
||||||
|
{
|
||||||
|
WindowSize = size;
|
||||||
|
}
|
||||||
|
void LzWindowDictionary::SetMinMatchAmount( int amount )
|
||||||
|
{
|
||||||
|
MinMatchAmount = amount;
|
||||||
|
}
|
||||||
|
void LzWindowDictionary::SetMaxMatchAmount( int amount )
|
||||||
|
{
|
||||||
|
MaxMatchAmount = amount;
|
||||||
|
}
|
||||||
|
void LzWindowDictionary::SetBlockSize( int size )
|
||||||
|
{
|
||||||
|
BlockSize = size;
|
||||||
|
WindowLength = size; // The window will work in blocks now
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add entries
|
||||||
|
void LzWindowDictionary::AddEntry( const QByteArray &DecompressedData, int offset )
|
||||||
|
{
|
||||||
|
OffsetList[ (quint8)( DecompressedData[ offset ] ) ] << offset;
|
||||||
|
}
|
||||||
|
void LzWindowDictionary::AddEntryRange( const QByteArray &DecompressedData, int offset, int length )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < length; i++ )
|
||||||
|
AddEntry( DecompressedData, offset + i );
|
||||||
|
}
|
||||||
|
67
WiiQt/lz77.h
67
WiiQt/lz77.h
@ -3,36 +3,47 @@
|
|||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
//class for daling with LZ77 compression
|
//class for dealing with LZ77 compression (version 0x10)
|
||||||
//! in most cases, you just want to use the static functions
|
//! in most cases, you just want to use the static functions
|
||||||
// QByteArray stuff = LZ77::Decompress( someCompressedData );
|
// QByteArray stuff = LZ77::Decompress( someCompressedData );
|
||||||
// QByteArray compressedData = LZ77::Compress( someData );
|
// QByteArray compressedData = LZ77::Compress( someData );
|
||||||
class LZ77
|
class LZ77
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum CompressionType
|
||||||
|
{
|
||||||
|
None, // not compressed
|
||||||
|
v10, // version 0x10
|
||||||
|
v11, // version 0x11
|
||||||
|
v10_w_magic // version 0x10 with "LZ77" magic bytes
|
||||||
|
};
|
||||||
|
|
||||||
LZ77();
|
LZ77();
|
||||||
void InsertNode( int r );
|
void InsertNode( int r );
|
||||||
void DeleteNode( int p );
|
void DeleteNode( int p );
|
||||||
void InitTree();
|
void InitTree();
|
||||||
|
|
||||||
//gets the offset in a bytearray if the lz77 magic word
|
//gets the offset in a bytearray of the lz77 magic word
|
||||||
static int GetLz77Offset( const QByteArray &data );
|
static int GetLz77Offset( const QByteArray &data );
|
||||||
|
|
||||||
//gets the decompressed size of a lz77 compressed buffer
|
//gets the decompressed size of a lz77 compressed buffer
|
||||||
static quint32 GetDecompressedSize( const QByteArray &data );
|
static quint32 GetDecompressedSize( const QByteArray &data );
|
||||||
|
|
||||||
//used internally by the static compression function
|
//decompress a buffer that is compressed with the 0x10 variant
|
||||||
QByteArray Compr( const QByteArray &ba );
|
static QByteArray Decompress_v10( const QByteArray &compressed, int offset );
|
||||||
|
|
||||||
static QByteArray Decompress( const QByteArray &compressed, int offset );
|
|
||||||
|
|
||||||
//finds the lz77 magic word and decompressed the data after it
|
|
||||||
// returns only the decompressed data. anything before the lz77 magic word is not included
|
|
||||||
static QByteArray Decompress( const QByteArray &compressed );
|
|
||||||
|
|
||||||
|
static QByteArray Compress( const QByteArray &ba, CompressionType type );
|
||||||
//compressed a qbytearray with the lz77 argorythm
|
//compressed a qbytearray with the lz77 argorythm
|
||||||
//returns a qbytearray ncluding the lz77 header
|
//returns a qbytearray ncluding the lz77 header
|
||||||
static QByteArray Compress( const QByteArray &ba );
|
static QByteArray Compress_v10( const QByteArray &ba, bool addMagic = true );
|
||||||
|
|
||||||
|
//check the type of archive, and get theoffset of the "LZ77" magic word in the case of v10_w_magic
|
||||||
|
static CompressionType GetCompressedType( const QByteArray &data, int *outOffset = NULL );
|
||||||
|
|
||||||
|
// decompress data and get whatever type of compression was used on the data
|
||||||
|
static QByteArray Decompress( const QByteArray &stuff, CompressionType *outType = NULL );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int lson[ 4097 ];
|
int lson[ 4097 ];
|
||||||
@ -43,6 +54,44 @@ private:
|
|||||||
int match_length;
|
int match_length;
|
||||||
int textsize;
|
int textsize;
|
||||||
int codesize;
|
int codesize;
|
||||||
|
|
||||||
|
|
||||||
|
//used internally by the static compression function
|
||||||
|
QByteArray Compr_v10( const QByteArray &ba, bool addMagic = true );
|
||||||
|
};
|
||||||
|
|
||||||
|
class LZ77_11
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LZ77_11();
|
||||||
|
static QByteArray Compress( const QByteArray &stuff );
|
||||||
|
static QByteArray Decompress( const QByteArray stuff );
|
||||||
|
};
|
||||||
|
|
||||||
|
class LzWindowDictionary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LzWindowDictionary();
|
||||||
|
|
||||||
|
QList<int> Search( const QByteArray &DecompressedData, quint32 offset, quint32 length );
|
||||||
|
void SlideWindow( int Amount );
|
||||||
|
void SlideBlock();
|
||||||
|
void RemoveOldEntries( quint8 index );
|
||||||
|
void SetWindowSize( int size );
|
||||||
|
void SetMinMatchAmount( int amount );
|
||||||
|
void SetMaxMatchAmount( int amount );
|
||||||
|
void SetBlockSize( int size );
|
||||||
|
void AddEntry( const QByteArray &DecompressedData, int offset );
|
||||||
|
void AddEntryRange( const QByteArray &DecompressedData, int offset, int length );
|
||||||
|
|
||||||
|
private:
|
||||||
|
int WindowSize;
|
||||||
|
int WindowStart;
|
||||||
|
int WindowLength;
|
||||||
|
int MinMatchAmount;
|
||||||
|
int MaxMatchAmount;
|
||||||
|
int BlockSize;
|
||||||
|
QList<int> OffsetList[ 0x100 ];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LZ77_H
|
#endif // LZ77_H
|
||||||
|
@ -440,7 +440,7 @@ bool NandDump::InstallNusItem( const NusJob &job )
|
|||||||
|
|
||||||
bool NandDump::InstallWad( Wad wad )
|
bool NandDump::InstallWad( Wad wad )
|
||||||
{
|
{
|
||||||
if( !wad.Tid() || wad.content_count() < 3 )
|
if( !wad.Tid() || wad.content_count() < 1 )
|
||||||
{
|
{
|
||||||
qWarning() << "NandDump::InstallNusItem -> invalid item";
|
qWarning() << "NandDump::InstallNusItem -> invalid item";
|
||||||
return false;
|
return false;
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
#define UPDATING_USER_AGENT "wii libnup/1.0"
|
#define UPDATING_USER_AGENT "wii libnup/1.0"
|
||||||
#define VIRTUAL_CONSOLE_USER_AGENT "libec-3.0.7.06111123"
|
#define VIRTUAL_CONSOLE_USER_AGENT "libec-3.0.7.06111123"
|
||||||
#define WIICONNECT24_USER_AGENT "WiiConnect24/1.0FC4plus1 (build 061114161108)"
|
#define WIICONNECT24_USER_AGENT "WiiConnect24/1.0FC4plus1 (build 061114161108)"
|
||||||
#define NUS_BASE_URL "http://ccs.shop.wii.com/ccs/download/"
|
//#define NUS_BASE_URL "http://ccs.shop.wii.com/ccs/download/"
|
||||||
|
#define NUS_BASE_URL "http://nus.cdn.shop.wii.com/ccs/download/"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,13 +29,13 @@ SaveBanner::SaveBanner( QByteArray stuff )
|
|||||||
qWarning() << "SaveBanner::SaveBanner -> bad file magic" << hex << qFromBigEndian( magic );
|
qWarning() << "SaveBanner::SaveBanner -> bad file magic" << hex << qFromBigEndian( magic );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//no clue what this stuff is, dont really need it though
|
|
||||||
//i suspect instructions for animation ? ( VC icons display forwards and backwards in the system menu )
|
f.read( (char*)&attributes, 4 );
|
||||||
//also speed is not always the same
|
f.read( (char*)&speeds, 2 );
|
||||||
quint32 tmp;
|
|
||||||
f.read( (char*)&tmp, 4 );
|
attributes = qFromBigEndian( attributes );
|
||||||
quint32 tmp2;
|
speeds = qFromBigEndian( speeds );
|
||||||
f.read( (char*)&tmp2, 4 );
|
|
||||||
f.seek( 0x20 );
|
f.seek( 0x20 );
|
||||||
|
|
||||||
quint16 name[ 0x20 ];
|
quint16 name[ 0x20 ];
|
||||||
@ -50,7 +50,48 @@ SaveBanner::SaveBanner( QByteArray stuff )
|
|||||||
|
|
||||||
saveTitle = saveTitle.trimmed();
|
saveTitle = saveTitle.trimmed();
|
||||||
|
|
||||||
//qDebug() << hex << qFromBigEndian( tmp ) << qFromBigEndian( tmp2 ) << saveTitle;
|
|
||||||
|
QString speedStr;
|
||||||
|
// 0 = lastimage, speed range from 1 - 3
|
||||||
|
for( int i = 0; i < 8; i++ )
|
||||||
|
{
|
||||||
|
speedStr += QString::number( ( speeds >> ( 2 * ( i ) ) ) & 3 );
|
||||||
|
if( i < 7 )
|
||||||
|
{
|
||||||
|
speedStr += " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString flags;
|
||||||
|
// nocopy bit
|
||||||
|
if( attributes & 1 )
|
||||||
|
{
|
||||||
|
flags += "nocopy";
|
||||||
|
}
|
||||||
|
|
||||||
|
// animation type bit
|
||||||
|
if( attributes & 0x10 )
|
||||||
|
{
|
||||||
|
if( !flags.isEmpty() )
|
||||||
|
{
|
||||||
|
flags += ", ";
|
||||||
|
}
|
||||||
|
flags += "forward and reverse";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !flags.isEmpty() )
|
||||||
|
{
|
||||||
|
flags += ", ";
|
||||||
|
}
|
||||||
|
flags += "loop";
|
||||||
|
}
|
||||||
|
flags = flags.leftJustified( 27, QChar( ' ' ) );
|
||||||
|
qDebug() << hex << //QString( "%1" ).arg( tmp, 8, 16, QChar( '0' ) ) <<
|
||||||
|
//QString( "%1" ).arg( speeds, 4, 16, QChar( '0' ) ) <<
|
||||||
|
speedStr <<
|
||||||
|
flags <<
|
||||||
|
saveTitle;
|
||||||
|
|
||||||
//QString title2;
|
//QString title2;
|
||||||
for( int i = 0; i < 0x20 && name2[ i ] != 0; i++ )
|
for( int i = 0; i < 0x20 && name2[ i ] != 0; i++ )
|
||||||
@ -72,33 +113,25 @@ SaveBanner::SaveBanner( QByteArray stuff )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the images that make up the icon
|
//get the images that make up the icon
|
||||||
while( f.pos() != size )
|
for( quint8 i = 0; i < 8 && f.pos() < size; i++ )
|
||||||
{
|
{
|
||||||
QByteArray icn = f.read( 0x1200 );
|
QByteArray icn = f.read( 0x1200 );
|
||||||
//check that there is actually data. some banners use all 0x00 for some images
|
|
||||||
bool null = true;
|
|
||||||
for( int i = 0; i < 0x1200; i++ )
|
|
||||||
{
|
|
||||||
if( icn.at( i ) )//this buffer contains at least 1 byte of data, try to turn it into an image
|
|
||||||
{
|
|
||||||
null = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( null )
|
|
||||||
{
|
|
||||||
//qDebug() << "skipping empty image";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make this texture int an image
|
//make this texture int an image
|
||||||
QImage iconImg = ConvertTextureToImage( icn, 0x30, 0x30 );
|
QImage iconImg = ConvertTextureToImage( icn, 0x30, 0x30 );
|
||||||
if( iconImg.isNull() )
|
if( iconImg.isNull() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//add the image to the list
|
//add the image to the list
|
||||||
iconImgs << iconImg;
|
iconImgs << iconImg;
|
||||||
}
|
|
||||||
|
if( !( ( speeds >> ( 2 * i ) ) & 3 ) )// this is the last image
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "imgCnt:" << iconImgs.size();
|
||||||
f.close();
|
f.close();
|
||||||
ok = true;
|
ok = true;
|
||||||
|
|
||||||
|
@ -6,20 +6,30 @@
|
|||||||
class SaveBanner
|
class SaveBanner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SaveBanner();
|
SaveBanner();
|
||||||
SaveBanner( const QString &bannerpath );
|
SaveBanner( const QString &bannerpath );
|
||||||
SaveBanner( QByteArray stuff );
|
SaveBanner( QByteArray stuff );
|
||||||
|
|
||||||
QImage BannerImg(){ return bannerImg; }
|
const QImage &BannerImg() const { return bannerImg; }
|
||||||
QList< QImage > IconImgs() { return iconImgs; }
|
const QList< QImage > &IconImgs() const { return iconImgs; }
|
||||||
|
|
||||||
QString Title(){ return saveTitle; }
|
const QString &Title() const { return saveTitle; }
|
||||||
QString SubTitle(){ return saveTitle2; }
|
const QString &SubTitle() const { return saveTitle2; }
|
||||||
|
|
||||||
|
quint32 Attributes() { return attributes; }
|
||||||
|
quint16 Speeds() { return speeds; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ok;
|
bool ok;
|
||||||
QImage bannerImg;
|
QImage bannerImg;
|
||||||
QList< QImage > iconImgs;
|
QList< QImage > iconImgs;
|
||||||
|
|
||||||
|
quint32 attributes; // bit 5 = animation type. if its set, the animation plays forward and backward
|
||||||
|
// if its not set, the animation just plays forward and loops
|
||||||
|
|
||||||
|
quint16 speeds; // 2 bits per frame. 0 signifies the last frame?
|
||||||
|
|
||||||
QString saveTitle;
|
QString saveTitle;
|
||||||
QString saveTitle2;
|
QString saveTitle2;
|
||||||
|
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
#define SD_IV { 0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98 };
|
#define SD_IV { 0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98 };
|
||||||
#define MD5_BLANKER { 0x0e, 0x65, 0x37, 0x81, 0x99, 0xbe, 0x45, 0x17, 0xab, 0x06, 0xec, 0x22, 0x45, 0x1a, 0x57, 0x93 };
|
#define MD5_BLANKER { 0x0e, 0x65, 0x37, 0x81, 0x99, 0xbe, 0x45, 0x17, 0xab, 0x06, 0xec, 0x22, 0x45, 0x1a, 0x57, 0x93 };
|
||||||
|
|
||||||
|
// debug helpers
|
||||||
|
#define DBG qDebug() << __PRETTY_FUNCTION__
|
||||||
|
#define WRN qWarning() << __PRETTY_FUNCTION__
|
||||||
|
|
||||||
|
|
||||||
#define TITLE_LATEST_VERSION 0xffff
|
#define TITLE_LATEST_VERSION 0xffff
|
||||||
//struct used to keep all the data about a NUS request together
|
//struct used to keep all the data about a NUS request together
|
||||||
|
100
WiiQt/u8.cpp
100
WiiQt/u8.cpp
@ -1,5 +1,4 @@
|
|||||||
#include "u8.h"
|
#include "u8.h"
|
||||||
#include "lz77.h"
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
//#include "md5.h"
|
//#include "md5.h"
|
||||||
#include "ash.h"
|
#include "ash.h"
|
||||||
@ -18,7 +17,8 @@ static quint32 swap24( quint32 i )
|
|||||||
U8::U8( bool initialize, int type, const QStringList &names )
|
U8::U8( bool initialize, int type, const QStringList &names )
|
||||||
{
|
{
|
||||||
ok = false;
|
ok = false;
|
||||||
isLz77 = false;
|
//isLz77 = false;
|
||||||
|
lz77Type = LZ77::None;
|
||||||
wii_cs_error = false;
|
wii_cs_error = false;
|
||||||
paths.clear();
|
paths.clear();
|
||||||
nestedU8s.clear();
|
nestedU8s.clear();
|
||||||
@ -37,7 +37,8 @@ U8::U8( bool initialize, int type, const QStringList &names )
|
|||||||
|
|
||||||
bool U8::CreateEmptyData()
|
bool U8::CreateEmptyData()
|
||||||
{
|
{
|
||||||
isLz77 = false;
|
//isLz77 = false;
|
||||||
|
lz77Type = LZ77::None;
|
||||||
nestedU8s.clear();
|
nestedU8s.clear();
|
||||||
data = QByteArray( 0x20, '\0' );
|
data = QByteArray( 0x20, '\0' );
|
||||||
|
|
||||||
@ -319,10 +320,15 @@ bool U8::ReplaceEntry( const QString &path, const QByteArray &nba, bool autoComp
|
|||||||
if( autoCompress )
|
if( autoCompress )
|
||||||
{
|
{
|
||||||
QByteArray oldData = data.mid( qFromBigEndian( fst[ entryToReplace ].FileOffset ), qFromBigEndian( fst[ entryToReplace ].FileLength ) );
|
QByteArray oldData = data.mid( qFromBigEndian( fst[ entryToReplace ].FileOffset ), qFromBigEndian( fst[ entryToReplace ].FileLength ) );
|
||||||
bool oldCompressed = ( LZ77::GetLz77Offset( oldData ) > -1 || IsAshCompressed( oldData ) );
|
LZ77::CompressionType ct = LZ77::GetCompressedType( oldData );
|
||||||
if( oldCompressed && LZ77::GetLz77Offset( newData ) == -1 && !IsAshCompressed( newData ) )
|
bool oldCompressed = ( ct != LZ77::None || IsAshCompressed( oldData ) );
|
||||||
|
if( oldCompressed && LZ77::GetCompressedType( newData ) == LZ77::None && !IsAshCompressed( newData ) )
|
||||||
{
|
{
|
||||||
newData = LZ77::Compress( newData );
|
if( ct == LZ77::None )
|
||||||
|
{
|
||||||
|
ct = LZ77::v10;
|
||||||
|
}
|
||||||
|
newData = LZ77::Compress( newData, ct );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,7 +946,8 @@ void U8::Load( const QByteArray &ba )
|
|||||||
{
|
{
|
||||||
ok = false;
|
ok = false;
|
||||||
wii_cs_error = false;
|
wii_cs_error = false;
|
||||||
isLz77 = false;
|
//isLz77 = false;
|
||||||
|
lz77Type = LZ77::None;
|
||||||
headerType = U8_Hdr_none;
|
headerType = U8_Hdr_none;
|
||||||
paths.clear();
|
paths.clear();
|
||||||
imetNames.clear();
|
imetNames.clear();
|
||||||
@ -955,14 +962,39 @@ void U8::Load( const QByteArray &ba )
|
|||||||
data = DecryptAsh( data );
|
data = DecryptAsh( data );
|
||||||
|
|
||||||
quint32 tmp;
|
quint32 tmp;
|
||||||
int off = LZ77::GetLz77Offset( data );
|
int off;
|
||||||
int off2 = GetU8Offset( data );
|
int off2;
|
||||||
|
LZ77::CompressionType type = LZ77::GetCompressedType( data, &off );
|
||||||
|
if( type == LZ77::v10 )
|
||||||
|
{
|
||||||
|
lz77Type = type;
|
||||||
|
data = LZ77::Decompress_v10( data, 0 );
|
||||||
|
}
|
||||||
|
else if( type == LZ77::v11 )
|
||||||
|
{
|
||||||
|
lz77Type = type;
|
||||||
|
data = LZ77_11::Decompress( data );
|
||||||
|
}
|
||||||
|
else if( type == LZ77::v10_w_magic )
|
||||||
|
{
|
||||||
|
off2 = GetU8Offset( data );
|
||||||
|
if( off2 >= 0 && off < off2 )
|
||||||
|
{
|
||||||
|
lz77Type = LZ77::v10_w_magic;
|
||||||
|
data = LZ77::Decompress_v10( data, off + 4 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
off2 = GetU8Offset( data );
|
||||||
|
//int off = LZ77::GetLz77Offset( data );
|
||||||
|
/*int off2 = GetU8Offset( data );
|
||||||
if( off != -1 && ( off2 == -1 || ( off2 != -1 && off < off2 ) ) )
|
if( off != -1 && ( off2 == -1 || ( off2 != -1 && off < off2 ) ) )
|
||||||
{
|
{
|
||||||
isLz77 = true;
|
//isLz77 = true;
|
||||||
data = LZ77::Decompress( data );
|
lz77Type = LZ77::v10_w_magic;
|
||||||
|
//data = LZ77::Decompress( data );
|
||||||
|
data = LZ77::Decompress_v10( data, off + 4 );
|
||||||
off2 = GetU8Offset( data );
|
off2 = GetU8Offset( data );
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if( off2 == -1 )
|
if( off2 == -1 )
|
||||||
{
|
{
|
||||||
@ -1111,8 +1143,9 @@ const QByteArray U8::GetData( const QString &str, bool onlyPayload )
|
|||||||
break;
|
break;
|
||||||
case U8_Hdr_IMD5:
|
case U8_Hdr_IMD5:
|
||||||
{
|
{
|
||||||
if( isLz77 )
|
//if( isLz77 )
|
||||||
ret = LZ77::Compress( ret );
|
if( lz77Type == LZ77::v10_w_magic )
|
||||||
|
ret = LZ77::Compress_v10( ret );
|
||||||
|
|
||||||
ret = AddIMD5( ret );
|
ret = AddIMD5( ret );
|
||||||
|
|
||||||
@ -1151,11 +1184,17 @@ const QByteArray U8::GetData( const QString &str, bool onlyPayload )
|
|||||||
//hexdump( ret, 0, 0x40 );
|
//hexdump( ret, 0, 0x40 );
|
||||||
if( onlyPayload )
|
if( onlyPayload )
|
||||||
{
|
{
|
||||||
if( LZ77::GetLz77Offset( ret ) != -1 )
|
LZ77::CompressionType ct;
|
||||||
ret = LZ77::Decompress( ret );
|
ret = LZ77::Decompress( ret, &ct );
|
||||||
|
if( ct == LZ77::None && IsAshCompressed( ret ) )
|
||||||
|
{
|
||||||
|
ret = DecryptAsh( ret );
|
||||||
|
}
|
||||||
|
//if( LZ77::GetLz77Offset( ret ) != -1 )
|
||||||
|
// ret = LZ77::Decompress( ret );
|
||||||
|
|
||||||
else if( IsAshCompressed( ret ) )
|
//else if( IsAshCompressed( ret ) )
|
||||||
ret = DecryptAsh( ret );
|
// ret = DecryptAsh( ret );
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1166,6 +1205,18 @@ quint32 U8::GetSize( const QString &str )
|
|||||||
{
|
{
|
||||||
return data.size();
|
return data.size();
|
||||||
}
|
}
|
||||||
|
//check if this is a path to a file in a nested archive
|
||||||
|
QMap<QString, U8 >::iterator i = nestedU8s.begin();
|
||||||
|
while( i != nestedU8s.constEnd() )
|
||||||
|
{
|
||||||
|
if( str.startsWith( i.key() ) && str != i.key() )
|
||||||
|
{
|
||||||
|
QString subPath = str;
|
||||||
|
subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash
|
||||||
|
return i.value().GetSize( subPath );
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
int index = FindEntry( str );
|
int index = FindEntry( str );
|
||||||
if( index < 0 )
|
if( index < 0 )
|
||||||
{
|
{
|
||||||
@ -1197,9 +1248,7 @@ bool U8::IsU8( const QByteArray &ba )
|
|||||||
if( IsAshCompressed( data ) )//decrypt ASH0 files
|
if( IsAshCompressed( data ) )//decrypt ASH0 files
|
||||||
data = DecryptAsh( data );
|
data = DecryptAsh( data );
|
||||||
|
|
||||||
int off = LZ77::GetLz77Offset( data );//decrypt LZ77
|
data = LZ77::Decompress( data );
|
||||||
if( off != -1 )
|
|
||||||
data = LZ77::Decompress( data );
|
|
||||||
|
|
||||||
QByteArray start = data.left( 5000 );
|
QByteArray start = data.left( 5000 );
|
||||||
return start.indexOf( "U\xAA\x38\x2d" ) != -1;
|
return start.indexOf( "U\xAA\x38\x2d" ) != -1;
|
||||||
@ -1413,10 +1462,11 @@ const QByteArray U8::AddIMET( int paddingType )
|
|||||||
soundSize = ret.size() - 0x20;
|
soundSize = ret.size() - 0x20;
|
||||||
|
|
||||||
ret = GetIMET( imetNames, paddingType, iconSize, bannerSize, soundSize );
|
ret = GetIMET( imetNames, paddingType, iconSize, bannerSize, soundSize );
|
||||||
if( isLz77 )//really? can the entire banner be lz77 compressed?
|
//if( isLz77 )//really? can the entire banner be lz77 compressed?
|
||||||
ret += LZ77::Compress( data );
|
// ret += LZ77::Compress( data );
|
||||||
else
|
//else
|
||||||
ret += data;
|
// ret += data;
|
||||||
|
ret += LZ77::Compress( data, lz77Type );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef U8_H
|
#ifndef U8_H
|
||||||
#define U8_H
|
#define U8_H
|
||||||
|
|
||||||
|
#include "lz77.h"
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
/*order of the names in the imet header
|
/*order of the names in the imet header
|
||||||
@ -163,7 +164,8 @@ private:
|
|||||||
bool wii_cs_error;
|
bool wii_cs_error;
|
||||||
|
|
||||||
//if this archive as a whole is lz77 compressed
|
//if this archive as a whole is lz77 compressed
|
||||||
bool isLz77;
|
//bool isLz77;
|
||||||
|
LZ77::CompressionType lz77Type;
|
||||||
|
|
||||||
QStringList imetNames;
|
QStringList imetNames;
|
||||||
int headerType;
|
int headerType;
|
||||||
|
Loading…
Reference in New Issue
Block a user