* add whatever local changes i have in the lz77 & u8 classes

* make everything build again
This commit is contained in:
giantpune 2012-01-11 05:29:59 +00:00
parent 59a7f2fcc7
commit 67064cb8bb
11 changed files with 2754 additions and 2184 deletions

View File

@ -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 );
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -1,221 +1,221 @@
#ifndef NANDBIN_H #ifndef NANDBIN_H
#define NANDBIN_H #define NANDBIN_H
#include "includes.h" #include "includes.h"
#include "blocks0to7.h" #include "blocks0to7.h"
#include "nandspare.h" #include "nandspare.h"
struct fst_t struct fst_t
{ {
quint8 filename[ 0xc ]; quint8 filename[ 0xc ];
quint8 attr; quint8 attr;
quint8 wtf; quint8 wtf;
quint16 sub; quint16 sub;
quint16 sib; quint16 sib;
quint32 size; quint32 size;
quint32 uid; quint32 uid;
quint16 gid; quint16 gid;
quint32 x3; quint32 x3;
quint16 fst_pos;//not really part of the nand structure, but needed when calculating hmac data quint16 fst_pos;//not really part of the nand structure, but needed when calculating hmac data
}; };
// class to deal with an encrypted wii nand dump // class to deal with an encrypted wii nand dump
// basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree() // basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree()
// extract files with GetFile() // extract files with GetFile()
//! you should verify anything written with this code before attempting to install it on you wii //! you should verify anything written with this code before attempting to install it on you wii
//once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree() //once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree()
class NandBin : public QObject class NandBin : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
//creates a NandBin object. if a path is given, it will call SetPath() on that path. though you cant check the return value //creates a NandBin object. if a path is given, it will call SetPath() on that path. though you cant check the return value
NandBin( QObject * parent = 0, const QString &path = QString() ); NandBin( QObject * parent = 0, const QString &path = QString() );
//destroys this object, and all its used resources ( closes the nand.bin file and deletes the filetree ) //destroys this object, and all its used resources ( closes the nand.bin file and deletes the filetree )
~NandBin(); ~NandBin();
//create a "blank" nand at the given path, with spare data and keeys.bin appended to the end //create a "blank" nand at the given path, with spare data and keeys.bin appended to the end
//keys should be a 0x400 byte array containing a keys.bin from bootmii //keys should be a 0x400 byte array containing a keys.bin from bootmii
//first8 should be a bytearray containing 0x108000 bytes - the first 8 blocks of the nand with spare data //first8 should be a bytearray containing 0x108000 bytes - the first 8 blocks of the nand with spare data
//badBlocks is a list of blocks to be marked bad, in the range 8 - 4079 //badBlocks is a list of blocks to be marked bad, in the range 8 - 4079
bool CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks = QList<quint16>() ); bool CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks = QList<quint16>() );
//sets the path of this object to path. returns false if it cannot open an already existing file //sets the path of this object to path. returns false if it cannot open an already existing file
//keys.bin should be in this same path if they are to be used //keys.bin should be in this same path if they are to be used
bool SetPath( const QString &path ); bool SetPath( const QString &path );
//try to read the filesystem and create a tree from its contents //try to read the filesystem and create a tree from its contents
//this takes care of the stuff like reading the keys, finding teh superblock, and creating the QTreeWidgetItem* tree //this takes care of the stuff like reading the keys, finding teh superblock, and creating the QTreeWidgetItem* tree
//icons given here will be the ones used when asking for that tree //icons given here will be the ones used when asking for that tree
bool InitNand( const QIcon &dirs = QIcon(), const QIcon &files = QIcon() ); bool InitNand( const QIcon &dirs = QIcon(), const QIcon &files = QIcon() );
//get a root item containing children that are actually entries in the nand dump //get a root item containing children that are actually entries in the nand dump
//the root itself is just a container to hold them all and can be deleted once its children are taken //the root itself is just a container to hold them all and can be deleted once its children are taken
//! all returned items are cloned and it is up to you to delete them ! //! all returned items are cloned and it is up to you to delete them !
//text is assigned to the items as follows... //text is assigned to the items as follows...
// 0 name // 0 name
// 1 entry # // 1 entry #
// 2 size // 2 size
// 3 uid // 3 uid
// 4 gid // 4 gid
// 5 x3 // 5 x3
// 6 mode // 6 mode
// 7 attr // 7 attr
QTreeWidgetItem *GetTree(); QTreeWidgetItem *GetTree();
//extracts an item( and all its children ) to a directory //extracts an item( and all its children ) to a directory
//this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns //this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns
bool ExtractToDir( QTreeWidgetItem *item, const QString &path ); bool ExtractToDir( QTreeWidgetItem *item, const QString &path );
//print a little info about the free space //print a little info about the free space
void ShowInfo(); void ShowInfo();
//set this to change ":" in names to "-" on etracting. //set this to change ":" in names to "-" on etracting.
//theres more illegal characters in FAT, but thes seems to be the only one that happens on the nand FS //theres more illegal characters in FAT, but thes seems to be the only one that happens on the nand FS
void SetFixNamesForFAT( bool fix = true ); void SetFixNamesForFAT( bool fix = true );
//returns the data that makes up the file of a given entry# //returns the data that makes up the file of a given entry#
const QByteArray GetFile( quint16 entry ); const QByteArray GetFile( quint16 entry );
//get data for a given path //get data for a given path
//! this function is slower than the above one, as it first iterates through the QTreeWidgetItems till it finds the right ono //! this function is slower than the above one, as it first iterates through the QTreeWidgetItems till it finds the right ono
//! and then end up calling the above one anyways. //! and then end up calling the above one anyways.
//the path should be a file, not folder //the path should be a file, not folder
//returns an empty array on failure //returns an empty array on failure
//path should start with "/" and items should be delimited by "/" //path should start with "/" and items should be delimited by "/"
//ie... /title/00000001/00000002/data/setting.txt //ie... /title/00000001/00000002/data/setting.txt
const QByteArray GetData( const QString &path ); const QByteArray GetData( const QString &path );
//returns the fats for this nand. //returns the fats for this nand.
const QList<quint16> GetFats() { return fats; } const QList<quint16> GetFats() { return fats; }
//get the fats for a given file //get the fats for a given file
const QList<quint16> GetFatsForFile( quint16 i ); const QList<quint16> GetFatsForFile( quint16 i );
//recurse folders and files and get all fats used for them //recurse folders and files and get all fats used for them
//! this is probably a more expensive function than you want to use //! this is probably a more expensive function than you want to use
//! it was added only to aid in checking for bugs and lost clusters //! it was added only to aid in checking for bugs and lost clusters
const QList<quint16> GetFatsForEntry( quint16 i ); const QList<quint16> GetFatsForEntry( quint16 i );
//use the above function to search and display lost clusters //use the above function to search and display lost clusters
void ShowLostClusters(); void ShowLostClusters();
const Blocks0to7 BootBlocks(){ return bootBlocks; } const Blocks0to7 BootBlocks(){ return bootBlocks; }
const QList<Boot2Info> Boot2Infos(); const QList<Boot2Info> Boot2Infos();
quint8 Boot1Version(); quint8 Boot1Version();
const QByteArray GetPage( quint32 pageNo, bool withEcc = false ); const QByteArray GetPage( quint32 pageNo, bool withEcc = false );
//create new entry //create new entry
//returns the index of the entry on success, or 0 on error //returns the index of the entry on success, or 0 on error
quint16 CreateEntry( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm ); quint16 CreateEntry( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm );
//delete a file/folder //delete a file/folder
bool Delete( const QString &path ); bool Delete( const QString &path );
//sets the data for a given file ( overwrites existing data ) //sets the data for a given file ( overwrites existing data )
bool SetData( quint16 idx, const QByteArray &data ); bool SetData( quint16 idx, const QByteArray &data );
//overloads the above function //overloads the above function
bool SetData( const QString &path, const QByteArray &data ); bool SetData( const QString &path, const QByteArray &data );
//write the current changes to the metadata( if you dont do this, then none of the other stuff youve done wont be saved ) //write the current changes to the metadata( if you dont do this, then none of the other stuff youve done wont be saved )
// but at the same time, you probably dont need to overuse this. ( no need to write metadata every time you make a single change ) // but at the same time, you probably dont need to overuse this. ( no need to write metadata every time you make a single change )
bool WriteMetaData(); bool WriteMetaData();
//functions to verify spare data //functions to verify spare data
bool CheckEcc( quint32 pageNo ); bool CheckEcc( quint32 pageNo );
bool CheckHmacData( quint16 entry ); bool CheckHmacData( quint16 entry );
//verify hmac stuff for a given supercluster //verify hmac stuff for a given supercluster
//expects 0x7f00 - 0x7ff0 //expects 0x7f00 - 0x7ff0
bool CheckHmacMeta( quint16 clNo ); bool CheckHmacMeta( quint16 clNo );
//wipe out all data within the nand FS, leaving only the root entry //wipe out all data within the nand FS, leaving only the root entry
//preserve all bad/reserved clusters //preserve all bad/reserved clusters
//if secure is true, overwrite old file data with 0xff //if secure is true, overwrite old file data with 0xff
bool Format( bool secure = true ); bool Format( bool secure = true );
//get the path of this nand //get the path of this nand
const QString FilePath(); const QString FilePath();
//get the keys.bin for this object //get the keys.bin for this object
const QByteArray Keys(); const QByteArray Keys();
private: private:
QByteArray key; QByteArray key;
qint32 loc_super; qint32 loc_super;
qint32 loc_fat; qint32 loc_fat;
qint32 loc_fst; qint32 loc_fst;
quint16 currentSuperCluster; quint16 currentSuperCluster;
quint32 superClusterVersion; quint32 superClusterVersion;
QString extractPath; QString extractPath;
QString nandPath; QString nandPath;
QFile f; QFile f;
int type; int type;
bool fatNames; bool fatNames;
QIcon groupIcon; QIcon groupIcon;
QIcon keyIcon; QIcon keyIcon;
NandSpare spare;//used to handle the hmac mumbojumbo NandSpare spare;//used to handle the hmac mumbojumbo
//read all the fst and remember them rather than seeking back and forth in the file all the time //read all the fst and remember them rather than seeking back and forth in the file all the time
// uses ~120KiB RAM // uses ~120KiB RAM
bool fstInited; bool fstInited;
fst_t fsts[ 0x17ff ]; fst_t fsts[ 0x17ff ];
//cache the fat to keep from having to look them up repeatedly //cache the fat to keep from having to look them up repeatedly
// uses ~64KiB // uses ~64KiB
QList<quint16>fats; QList<quint16>fats;
int GetDumpType( quint64 fileSize ); int GetDumpType( quint64 fileSize );
bool GetKey( int type ); bool GetKey( int type );
const QByteArray ReadKeyfile( const QString &path, quint8 type );//type 0 for nand key, type 1 for hmac const QByteArray ReadKeyfile( const QString &path, quint8 type );//type 0 for nand key, type 1 for hmac
qint32 FindSuperblock(); qint32 FindSuperblock();
quint16 GetFAT( quint16 fat_entry ); quint16 GetFAT( quint16 fat_entry );
fst_t GetFST( quint16 entry ); fst_t GetFST( quint16 entry );
const QByteArray GetCluster( quint16 cluster_entry, bool decrypt = true ); const QByteArray GetCluster( quint16 cluster_entry, bool decrypt = true );
const QByteArray GetFile( fst_t fst ); const QByteArray GetFile( fst_t fst );
const QString FstName( fst_t fst ); const QString FstName( fst_t fst );
bool ExtractFST( quint16 entry, const QString &path, bool singleFile = false ); bool ExtractFST( quint16 entry, const QString &path, bool singleFile = false );
bool ExtractDir( fst_t fst, const QString &parent ); bool ExtractDir( fst_t fst, const QString &parent );
bool ExtractFile( fst_t fst, const QString &parent ); bool ExtractFile( fst_t fst, const QString &parent );
QTreeWidgetItem *CreateItem( QTreeWidgetItem *parent, const QString &name, quint32 size, quint16 entry, quint32 uid, quint32 gid, quint32 x3, quint8 attr, quint8 wtf); QTreeWidgetItem *CreateItem( QTreeWidgetItem *parent, const QString &name, quint32 size, quint16 entry, quint32 uid, quint32 gid, quint32 x3, quint8 attr, quint8 wtf);
QTreeWidgetItem *root; QTreeWidgetItem *root;
bool AddChildren( QTreeWidgetItem *parent, quint16 entry ); bool AddChildren( QTreeWidgetItem *parent, quint16 entry );
QTreeWidgetItem *ItemFromPath( const QString &path ); QTreeWidgetItem *ItemFromPath( const QString &path );
QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent ); QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent );
//holds info about boot1 & 2 //holds info about boot1 & 2
Blocks0to7 bootBlocks; Blocks0to7 bootBlocks;
bool WriteCluster( quint32 pageNo, const QByteArray &data, const QByteArray &hmac ); bool WriteCluster( quint32 pageNo, const QByteArray &data, const QByteArray &hmac );
bool WriteDecryptedCluster( quint32 pageNo, const QByteArray &data, fst_t fst, quint16 idx ); bool WriteDecryptedCluster( quint32 pageNo, const QByteArray &data, fst_t fst, quint16 idx );
bool WritePage( quint32 pageNo, const QByteArray &data ); bool WritePage( quint32 pageNo, const QByteArray &data );
quint16 CreateNode( const QString &name, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm ); quint16 CreateNode( const QString &name, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm );
bool DeleteItem( QTreeWidgetItem *item ); bool DeleteItem( QTreeWidgetItem *item );
//find a parent entry for a path to be created - "/title/00000001" should give the entry for "/title" //find a parent entry for a path to be created - "/title/00000001" should give the entry for "/title"
QTreeWidgetItem *GetParent( const QString &path ); QTreeWidgetItem *GetParent( const QString &path );
QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL ); QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL );
QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL ); QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL );
signals: signals:
//connect to these to receive messages from this object //connect to these to receive messages from this object
//so far, many errors are only outputting to qDebug() and qWarning(). //so far, many errors are only outputting to qDebug() and qWarning().
void SendError( QString ); void SendError( QString );
void SendText( QString ); void SendText( QString );
}; };
#endif // NANDBIN_H #endif // NANDBIN_H

View File

@ -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;

View File

@ -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/"

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
} }

View File

@ -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;