mirror of
https://github.com/martravi/wiiqt.git
synced 2024-11-26 02:54:19 +01:00
* TMD:: use reserved2 for fakesigning. "zeros" is actually part of the region and breaks things
* nandBin:: if SFFS generation rolls around to 0, write all 16 superclusters
This commit is contained in:
parent
c96add47e3
commit
15f5715c52
318
WiiQt/lz77.cpp
318
WiiQt/lz77.cpp
@ -23,10 +23,10 @@ void LZ77::InitTree()
|
|||||||
int i;
|
int i;
|
||||||
int N = 4096;
|
int N = 4096;
|
||||||
for( i = N + 1; i <= N + 256; i++ )
|
for( i = N + 1; i <= N + 256; i++ )
|
||||||
rson[ i ] = N;
|
rson[ i ] = N;
|
||||||
|
|
||||||
for( i = 0; i < N; i++ )
|
for( i = 0; i < N; i++ )
|
||||||
dad[ i ] = N;
|
dad[ i ] = N;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LZ77::DeleteNode( int p )
|
void LZ77::DeleteNode( int p )
|
||||||
@ -35,41 +35,41 @@ void LZ77::DeleteNode( int p )
|
|||||||
int q;
|
int q;
|
||||||
|
|
||||||
if( dad[ p ] == N )
|
if( dad[ p ] == N )
|
||||||
return; /* not in tree */
|
return; /* not in tree */
|
||||||
|
|
||||||
if( rson[ p ] == N )
|
if( rson[ p ] == N )
|
||||||
q = lson[ p ];
|
q = lson[ p ];
|
||||||
|
|
||||||
else if( lson[ p ] == N )
|
else if( lson[ p ] == N )
|
||||||
q = rson[ p ];
|
q = rson[ p ];
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
q = lson[ p ];
|
q = lson[ p ];
|
||||||
|
|
||||||
if( rson[ q ] != N )
|
if( rson[ q ] != N )
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
q = rson[ q ];
|
q = rson[ q ];
|
||||||
}
|
}
|
||||||
while( rson[ q ] != N );
|
while( rson[ q ] != N );
|
||||||
|
|
||||||
rson[ dad[ q ] ] = lson[ q ];
|
rson[ dad[ q ] ] = lson[ q ];
|
||||||
dad[ lson[ q ] ] = dad[ q ];
|
dad[ lson[ q ] ] = dad[ q ];
|
||||||
|
|
||||||
lson[ q ] = lson[ p ];
|
lson[ q ] = lson[ p ];
|
||||||
dad[ lson[ p ] ] = q;
|
dad[ lson[ p ] ] = q;
|
||||||
}
|
}
|
||||||
rson[ q ] = rson[ p ];
|
rson[ q ] = rson[ p ];
|
||||||
dad[ rson[ p ] ] = q;
|
dad[ rson[ p ] ] = q;
|
||||||
}
|
}
|
||||||
dad[ q ] = dad[ p ];
|
dad[ q ] = dad[ p ];
|
||||||
|
|
||||||
if( rson[ dad[ p ] ] == p )
|
if( rson[ dad[ p ] ] == p )
|
||||||
rson[ dad[ p ] ] = q;
|
rson[ dad[ p ] ] = q;
|
||||||
else
|
else
|
||||||
lson[ dad[ p ] ] = q;
|
lson[ dad[ p ] ] = q;
|
||||||
|
|
||||||
dad[ p ] = N;
|
dad[ p ] = N;
|
||||||
}
|
}
|
||||||
@ -85,38 +85,38 @@ void LZ77::InsertNode( int r )
|
|||||||
match_length = 0;
|
match_length = 0;
|
||||||
for( ; ; )
|
for( ; ; )
|
||||||
{
|
{
|
||||||
if( cmp >= 0 )
|
if( cmp >= 0 )
|
||||||
{
|
{
|
||||||
if( rson[ p ] != N )
|
if( rson[ p ] != N )
|
||||||
p = rson[ p ];
|
p = rson[ p ];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rson[ p ] = r;
|
rson[ p ] = r;
|
||||||
dad[ r ] = p;
|
dad[ r ] = p;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( lson[ p ] != N )
|
if ( lson[ p ] != N )
|
||||||
p = lson[ p ];
|
p = lson[ p ];
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lson[ p ] = r;
|
lson[ p ] = r;
|
||||||
dad[ r ] = p;
|
dad[ r ] = p;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for( i = 1; i < F; i++ )
|
for( i = 1; i < F; i++ )
|
||||||
if( ( cmp = text_buf[ r + i ] - text_buf[ p + i ] ) != 0 )
|
if( ( cmp = text_buf[ r + i ] - text_buf[ p + i ] ) != 0 )
|
||||||
break;
|
break;
|
||||||
if( i > match_length )
|
if( i > match_length )
|
||||||
{
|
{
|
||||||
match_position = p;
|
match_position = p;
|
||||||
if( ( match_length = i ) >= F )
|
if( ( match_length = i ) >= F )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dad[ r ] = dad[ p ];
|
dad[ r ] = dad[ p ];
|
||||||
@ -126,10 +126,10 @@ void LZ77::InsertNode( int r )
|
|||||||
dad[ rson[ p ] ] = r;
|
dad[ rson[ p ] ] = r;
|
||||||
|
|
||||||
if( rson[ dad[ p ] ] == p )
|
if( rson[ dad[ p ] ] == p )
|
||||||
rson[ dad[ p ] ] = r;
|
rson[ dad[ p ] ] = r;
|
||||||
|
|
||||||
else
|
else
|
||||||
lson[ dad[ p ] ] = r;
|
lson[ dad[ p ] ] = r;
|
||||||
|
|
||||||
dad[ p ] = N;
|
dad[ p ] = N;
|
||||||
}
|
}
|
||||||
@ -139,15 +139,15 @@ quint32 LZ77::GetDecompressedSize( const QByteArray &data )
|
|||||||
int off = GetLz77Offset( data );
|
int off = GetLz77Offset( data );
|
||||||
if( off == -1 )
|
if( off == -1 )
|
||||||
{
|
{
|
||||||
qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic";
|
qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
QByteArray ba = data;
|
QByteArray ba = data;
|
||||||
QBuffer buf( &ba );
|
QBuffer buf( &ba );
|
||||||
if( !buf.open( QBuffer::ReadOnly ) )
|
if( !buf.open( QBuffer::ReadOnly ) )
|
||||||
{
|
{
|
||||||
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 + 4 );
|
||||||
|
|
||||||
@ -173,15 +173,15 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
|||||||
QBuffer infile( &crap );
|
QBuffer infile( &crap );
|
||||||
if( !infile.open( QBuffer::ReadOnly ) )
|
if( !infile.open( QBuffer::ReadOnly ) )
|
||||||
{
|
{
|
||||||
qWarning() << "Can't create buffer 1";
|
qWarning() << "Can't create buffer 1";
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
QByteArray ret;
|
QByteArray ret;
|
||||||
QBuffer outfile( &ret );
|
QBuffer outfile( &ret );
|
||||||
if( !outfile.open( QBuffer::ReadWrite ) )
|
if( !outfile.open( QBuffer::ReadWrite ) )
|
||||||
{
|
{
|
||||||
qWarning() << "Can't create buffer 2";
|
qWarning() << "Can't create buffer 2";
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 gbaheader;
|
quint32 gbaheader;
|
||||||
@ -192,7 +192,7 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
|||||||
quint8 text_buf[ N + 17 ];
|
quint8 text_buf[ N + 17 ];
|
||||||
|
|
||||||
for( i = 0; i < N - F; i++ )
|
for( i = 0; i < N - F; i++ )
|
||||||
text_buf[ i ] = 0xdf;
|
text_buf[ i ] = 0xdf;
|
||||||
|
|
||||||
r = N - F;
|
r = N - F;
|
||||||
flags = 7;
|
flags = 7;
|
||||||
@ -200,51 +200,51 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
|||||||
|
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
flags <<= 1;
|
flags <<= 1;
|
||||||
z++;
|
z++;
|
||||||
if( z == 8 )
|
if( z == 8 )
|
||||||
{
|
{
|
||||||
if( !infile.getChar( &ch ) )
|
if( !infile.getChar( &ch ) )
|
||||||
break;
|
break;
|
||||||
flags = (quint8) ch;
|
flags = (quint8) ch;
|
||||||
z = 0;
|
z = 0;
|
||||||
}
|
}
|
||||||
if( ( flags & 0x80 ) == 0 )
|
if( ( flags & 0x80 ) == 0 )
|
||||||
{
|
{
|
||||||
if( !infile.getChar( &ch ) )
|
if( !infile.getChar( &ch ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if( cur_size < decomp_size )
|
if( cur_size < decomp_size )
|
||||||
outfile.putChar( ch );
|
outfile.putChar( ch );
|
||||||
|
|
||||||
text_buf[ r++ ] = ch;
|
text_buf[ r++ ] = ch;
|
||||||
r &= ( N - 1 );
|
r &= ( N - 1 );
|
||||||
cur_size++;
|
cur_size++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( !infile.getChar( &ch ) )
|
if( !infile.getChar( &ch ) )
|
||||||
break;
|
break;
|
||||||
i = (quint8)ch;
|
i = (quint8)ch;
|
||||||
|
|
||||||
if( !infile.getChar( &ch ) )
|
if( !infile.getChar( &ch ) )
|
||||||
break;
|
break;
|
||||||
j = (quint8)ch;
|
j = (quint8)ch;
|
||||||
|
|
||||||
j = j | ( (i << 8) & 0xf00 );
|
j = j | ( (i << 8) & 0xf00 );
|
||||||
i = ( ( i >> 4 ) & 0x0f ) + threshold;
|
i = ( ( i >> 4 ) & 0x0f ) + threshold;
|
||||||
|
|
||||||
for( k = 0; k <= i; k++ )
|
for( k = 0; k <= i; k++ )
|
||||||
{
|
{
|
||||||
ch = text_buf[ ( r - j - 1 ) & ( N - 1 ) ];
|
ch = text_buf[ ( r - j - 1 ) & ( N - 1 ) ];
|
||||||
if( cur_size < decomp_size )
|
if( cur_size < decomp_size )
|
||||||
outfile.putChar( ch );
|
outfile.putChar( ch );
|
||||||
|
|
||||||
text_buf[ r++ ] = ch;
|
text_buf[ r++ ] = ch;
|
||||||
r &= ( N - 1 );
|
r &= ( N - 1 );
|
||||||
cur_size++;
|
cur_size++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -255,8 +255,8 @@ QByteArray LZ77::Decompress( const QByteArray &compressed )
|
|||||||
int off = GetLz77Offset( compressed );
|
int off = GetLz77Offset( compressed );
|
||||||
if( off < 0 )
|
if( off < 0 )
|
||||||
{
|
{
|
||||||
qWarning() << "LZ77::Decompress -> data is not compressed";
|
qWarning() << "LZ77::Decompress -> data is not compressed";
|
||||||
return compressed;
|
return compressed;
|
||||||
}
|
}
|
||||||
return Decompress( compressed, off );
|
return Decompress( compressed, off );
|
||||||
}
|
}
|
||||||
@ -285,15 +285,15 @@ QByteArray LZ77::Compr( const QByteArray &ba )
|
|||||||
QBuffer infile( &crap );
|
QBuffer infile( &crap );
|
||||||
if( !infile.open( QBuffer::ReadOnly ) )
|
if( !infile.open( QBuffer::ReadOnly ) )
|
||||||
{
|
{
|
||||||
qWarning() << "Can't create buffer 1";
|
qWarning() << "Can't create buffer 1";
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
QByteArray ret;
|
QByteArray ret;
|
||||||
QBuffer output( &ret );
|
QBuffer output( &ret );
|
||||||
if( !output.open( QBuffer::ReadWrite ) )
|
if( !output.open( QBuffer::ReadWrite ) )
|
||||||
{
|
{
|
||||||
qWarning() << "Can't create buffer 2";
|
qWarning() << "Can't create buffer 2";
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
output.putChar( 'L' );
|
output.putChar( 'L' );
|
||||||
output.putChar( 'Z' );
|
output.putChar( 'Z' );
|
||||||
@ -310,83 +310,83 @@ QByteArray LZ77::Compr( const QByteArray &ba )
|
|||||||
r = N - F;
|
r = N - F;
|
||||||
|
|
||||||
for( i = s; i < r; i++ )
|
for( i = s; i < r; i++ )
|
||||||
text_buf[ i ] = 0xffff;
|
text_buf[ i ] = 0xffff;
|
||||||
|
|
||||||
for( len = 0; len < F && infile.getChar( &ch ); len++ )
|
for( len = 0; len < F && infile.getChar( &ch ); len++ )
|
||||||
text_buf[ r + len ] = (quint8)ch;
|
text_buf[ r + len ] = (quint8)ch;
|
||||||
|
|
||||||
if( ( textsize = len ) == 0)
|
if( ( textsize = len ) == 0)
|
||||||
return ba;
|
return ba;
|
||||||
|
|
||||||
for( i = 1; i <= F; i++ )
|
for( i = 1; i <= F; i++ )
|
||||||
InsertNode( r - i );
|
InsertNode( r - i );
|
||||||
|
|
||||||
InsertNode( r );
|
InsertNode( r );
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if( match_length > len )
|
if( match_length > len )
|
||||||
match_length = len;
|
match_length = len;
|
||||||
|
|
||||||
if( match_length <= threshold )
|
if( match_length <= threshold )
|
||||||
{
|
{
|
||||||
match_length = 1;
|
match_length = 1;
|
||||||
code_buf[ code_buf_ptr++ ] = text_buf[ r ];
|
code_buf[ code_buf_ptr++ ] = text_buf[ r ];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
code_buf[ 0 ] |= mask;
|
code_buf[ 0 ] |= mask;
|
||||||
|
|
||||||
code_buf[ code_buf_ptr++ ] = (quint8)
|
code_buf[ code_buf_ptr++ ] = (quint8)
|
||||||
( ( ( r - match_position - 1 ) >> 8) & 0x0f ) |
|
( ( ( r - match_position - 1 ) >> 8) & 0x0f ) |
|
||||||
( ( match_length - ( threshold + 1 ) ) << 4 );
|
( ( match_length - ( threshold + 1 ) ) << 4 );
|
||||||
|
|
||||||
code_buf[ code_buf_ptr++ ] = (quint8)( ( r - match_position - 1 ) & 0xff );
|
code_buf[ code_buf_ptr++ ] = (quint8)( ( r - match_position - 1 ) & 0xff );
|
||||||
}
|
}
|
||||||
if( ( mask >>= 1 ) == 0 )
|
if( ( mask >>= 1 ) == 0 )
|
||||||
{
|
{
|
||||||
for( i = 0; i < code_buf_ptr; i++ )
|
for( i = 0; i < code_buf_ptr; i++ )
|
||||||
output.putChar( (quint8)code_buf[ i ] );
|
output.putChar( (quint8)code_buf[ i ] );
|
||||||
|
|
||||||
codesize += code_buf_ptr;
|
codesize += code_buf_ptr;
|
||||||
code_buf[ 0 ] = 0; code_buf_ptr = 1;
|
code_buf[ 0 ] = 0; code_buf_ptr = 1;
|
||||||
mask = 0x80;
|
mask = 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_match_length = match_length;
|
last_match_length = match_length;
|
||||||
for( i = 0; i < last_match_length && infile.getChar( &ch ); i++ )
|
for( i = 0; i < last_match_length && infile.getChar( &ch ); i++ )
|
||||||
{
|
{
|
||||||
DeleteNode( s );
|
DeleteNode( s );
|
||||||
text_buf[ s ] = (quint8)ch;
|
text_buf[ s ] = (quint8)ch;
|
||||||
if( s < F - 1 )
|
if( s < F - 1 )
|
||||||
text_buf[ s + N ] = (quint8)ch;
|
text_buf[ s + N ] = (quint8)ch;
|
||||||
|
|
||||||
s = ( s + 1 ) & ( N - 1 );
|
s = ( s + 1 ) & ( N - 1 );
|
||||||
r = ( r + 1 ) & ( N - 1 );
|
r = ( r + 1 ) & ( N - 1 );
|
||||||
InsertNode( r );
|
InsertNode( r );
|
||||||
}
|
}
|
||||||
|
|
||||||
while( i++ < last_match_length )
|
while( i++ < last_match_length )
|
||||||
{
|
{
|
||||||
DeleteNode( s );
|
DeleteNode( s );
|
||||||
s = ( s + 1 ) & ( N - 1 );
|
s = ( s + 1 ) & ( N - 1 );
|
||||||
r = ( r + 1 ) & ( N - 1 );
|
r = ( r + 1 ) & ( N - 1 );
|
||||||
if( --len != 0 )
|
if( --len != 0 )
|
||||||
InsertNode( r );
|
InsertNode( r );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( len > 0 );
|
while( len > 0 );
|
||||||
|
|
||||||
if( code_buf_ptr > 1 )
|
if( code_buf_ptr > 1 )
|
||||||
{
|
{
|
||||||
for( i = 0; i < code_buf_ptr; i++ )
|
for( i = 0; i < code_buf_ptr; i++ )
|
||||||
output.putChar( (quint8)code_buf[ i ] );
|
output.putChar( (quint8)code_buf[ i ] );
|
||||||
|
|
||||||
codesize += code_buf_ptr;
|
codesize += code_buf_ptr;
|
||||||
}
|
}
|
||||||
int padding = codesize % 4;
|
int padding = codesize % 4;
|
||||||
if( padding != 0 )
|
if( padding != 0 )
|
||||||
output.write( QByteArray( 4 - padding, '\0' ) );
|
output.write( QByteArray( 4 - padding, '\0' ) );
|
||||||
|
|
||||||
infile.close();
|
infile.close();
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -219,133 +219,6 @@ bool NandBin::Format( bool secure )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // this boots ok on real HW. trap15 thinks these reserved blocks are IOS's way of marking ones it thinks are bad
|
|
||||||
bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks )
|
|
||||||
{
|
|
||||||
#ifndef NAND_BIN_CAN_WRITE
|
|
||||||
qWarning() << __FILE__ << "was built without write support";
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
if( keys.size() != 0x400 || first8.size() != 0x108000 )
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for( quint16 i = 0; i < 0x40; i++ )
|
|
||||||
{
|
|
||||||
if( badBlocks.contains( i / 8 ) )
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the first 8 is not supported";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( quint16 i = 0x7f00; i < 0x8000; i++ )
|
|
||||||
{
|
|
||||||
if( badBlocks.contains( i / 8 ) )
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the superclusters not supported";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( f.isOpen() )
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
//create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end
|
|
||||||
f.setFileName( path );
|
|
||||||
if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) )
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> can't create file" << path;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write( first8 );
|
|
||||||
QByteArray block( 0x4200, 0xff );//generic empty block
|
|
||||||
for( quint16 i = 0; i < 0x7fc0; i++ )
|
|
||||||
f.write( block );
|
|
||||||
|
|
||||||
f.write( keys );
|
|
||||||
if( f.pos() != 0x21000400 )//no room left on the drive?
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//setup variables
|
|
||||||
nandPath = path;
|
|
||||||
currentSuperCluster = 0x7f00;
|
|
||||||
superClusterVersion = 1;
|
|
||||||
type = 2;
|
|
||||||
fats.clear();
|
|
||||||
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
|
|
||||||
|
|
||||||
for( quint16 i = 0; i < 0x17ff; i++ )
|
|
||||||
fsts[ i ].fst_pos = i;
|
|
||||||
|
|
||||||
//reserve blocks 0 - 7
|
|
||||||
for( quint16 i = 0; i < 0x40; i++ )
|
|
||||||
{
|
|
||||||
fats << 0xfffc;
|
|
||||||
}
|
|
||||||
//find 90 blocks to reserve. they always appear to be close to the end of the nand
|
|
||||||
//TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle
|
|
||||||
//sometimes IOS adds more
|
|
||||||
quint16 bCnt = badBlocks.size();
|
|
||||||
quint16 offset = 0;
|
|
||||||
for( quint16 i = 0; i < bCnt; i++ )
|
|
||||||
{
|
|
||||||
if( i >= 3998 )
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//mark all the "normal" blocks - free, or bad
|
|
||||||
for( quint16 i = 0x40; i < 0x7cf0 - offset; i++ )
|
|
||||||
{
|
|
||||||
if( badBlocks.contains( i / 8 ) )
|
|
||||||
fats << 0xfffd;
|
|
||||||
else
|
|
||||||
fats << 0xfffe;
|
|
||||||
|
|
||||||
}
|
|
||||||
//mark the 90 reserved ones from above and reserve the superclusters
|
|
||||||
for( quint16 i = 0x7cf0 - offset; i < 0x8000; i++ )
|
|
||||||
{
|
|
||||||
fats << 0xfffc;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make the root item
|
|
||||||
fsts[ 0 ].filename[ 0 ] = '/';
|
|
||||||
fsts[ 0 ].attr = 0x16;
|
|
||||||
fsts[ 0 ].sib = 0xffff;
|
|
||||||
fsts[ 0 ].sub = 0xffff;
|
|
||||||
|
|
||||||
fstInited = true;
|
|
||||||
|
|
||||||
//set keys
|
|
||||||
QByteArray hmacKey = keys.mid( 0x144, 0x14 );
|
|
||||||
spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data
|
|
||||||
key = keys.mid( 0x158, 0x10 );
|
|
||||||
|
|
||||||
//write the metada to each of the superblocks
|
|
||||||
for( quint8 i = 0; i < 0x10; i++ )
|
|
||||||
{
|
|
||||||
if( !WriteMetaData() )
|
|
||||||
{
|
|
||||||
qWarning() << "NandBin::CreateNew -> error writing superblock" << i;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//build the tree
|
|
||||||
if( root )
|
|
||||||
delete root;
|
|
||||||
root = new QTreeWidgetItem( QStringList() << nandPath );
|
|
||||||
AddChildren( root, 0 );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
QTreeWidgetItem *NandBin::GetTree()
|
QTreeWidgetItem *NandBin::GetTree()
|
||||||
{
|
{
|
||||||
//qDebug() << "NandBin::GetTree()";
|
//qDebug() << "NandBin::GetTree()";
|
||||||
@ -1344,10 +1217,10 @@ quint16 NandBin::CreateNode( const QString &name, quint32 uid, quint16 gid, quin
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray n = name.toLatin1().data();
|
QByteArray n = name.toLatin1();
|
||||||
n.resize( 12 );
|
n.resize( 12 );
|
||||||
//qDebug() << "will add entry for" << n << "at" << hex << i;
|
//qDebug() << "will add entry for" << n << "at" << hex << i;
|
||||||
memcpy( &fsts[ i ].filename, n, 12 );
|
memcpy( &fsts[ i ].filename, n.data(), 12 );
|
||||||
fsts[ i ].attr = attr;
|
fsts[ i ].attr = attr;
|
||||||
fsts[ i ].wtf = 0;
|
fsts[ i ].wtf = 0;
|
||||||
if( ( attr & 3 ) == 2 )
|
if( ( attr & 3 ) == 2 )
|
||||||
@ -1552,14 +1425,14 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
|||||||
{
|
{
|
||||||
fats.replace( cl, 0xfffe );
|
fats.replace( cl, 0xfffe );
|
||||||
}
|
}
|
||||||
// qDebug() << "delete loop done. freed" << toFree.size() << "clusters";
|
// qDebug() << "delete loop done. freed" << toFree.size() << "clusters";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
qDebug() << "deleting children of" << item->text( 0 );
|
qDebug() << "deleting children of" << item->text( 0 );
|
||||||
quint32 cnt = item->childCount();//delete all the children of this item
|
quint32 cnt = item->childCount();//delete all the children of this item
|
||||||
// qDebug() << cnt << "childern";
|
// qDebug() << cnt << "childern";
|
||||||
for( quint32 i = cnt; i > 0; i-- )
|
for( quint32 i = cnt; i > 0; i-- )
|
||||||
{
|
{
|
||||||
if( !DeleteItem( item->child( i - 1 ) ) )
|
if( !DeleteItem( item->child( i - 1 ) ) )
|
||||||
@ -1575,7 +1448,7 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
|||||||
memset( &fsts[ idx ], 0, sizeof( fst_t ) ); //clear this entry
|
memset( &fsts[ idx ], 0, sizeof( fst_t ) ); //clear this entry
|
||||||
fsts[ idx ].fst_pos = idx; //reset this
|
fsts[ idx ].fst_pos = idx; //reset this
|
||||||
QTreeWidgetItem *d = par->takeChild( pId );
|
QTreeWidgetItem *d = par->takeChild( pId );
|
||||||
// qDebug() << "deleting tree item" << d->text( 0 );
|
// qDebug() << "deleting tree item" << d->text( 0 );
|
||||||
delete d;
|
delete d;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1741,9 +1614,10 @@ bool NandBin::WriteMetaData()
|
|||||||
|
|
||||||
b.write( "SFFS" ); //magic word
|
b.write( "SFFS" ); //magic word
|
||||||
tmp = qFromBigEndian( nextClusterVersion );
|
tmp = qFromBigEndian( nextClusterVersion );
|
||||||
b.write( (const char*)&tmp, 4 ); //version
|
b.write( (const char*)&tmp, 4 ); //version
|
||||||
tmp = qFromBigEndian( (quint32)0x10 );
|
tmp = qFromBigEndian( (quint32)0 );
|
||||||
b.write( (const char*)&tmp, 4 ); //wiibrew says its always 0x10. but mine is 0
|
//tmp = qFromBigEndian( (quint32)0x10 ); //wiibrew says its always 0x10. but mine is 0
|
||||||
|
b.write( (const char*)&tmp, 4 );
|
||||||
//qDebug() << "writing the fats at" << hex << (quint32)b.pos();
|
//qDebug() << "writing the fats at" << hex << (quint32)b.pos();
|
||||||
|
|
||||||
//write all the fats
|
//write all the fats
|
||||||
@ -1799,10 +1673,22 @@ bool NandBin::WriteMetaData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentSuperCluster = nextSuperCluster;
|
currentSuperCluster = nextSuperCluster;
|
||||||
superClusterVersion = nextClusterVersion; //probably need to put some magic here in case the version wraps around back to 0
|
superClusterVersion = nextClusterVersion;
|
||||||
|
|
||||||
//make sure all the data is really written
|
|
||||||
f.flush();
|
//make sure all the data is really written
|
||||||
|
f.flush();
|
||||||
|
|
||||||
|
// in case the version wraps around back to 0
|
||||||
|
if( !superClusterVersion )
|
||||||
|
{
|
||||||
|
qDebug() << "NandBin::WriteMetaData -> SFFS generation rolled back to 0";
|
||||||
|
for( quint16 i = 0; i < 15; i++ )
|
||||||
|
{
|
||||||
|
if( !WriteMetaData() )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1908,7 +1794,7 @@ bool NandBin::CheckHmacData( quint16 entry )
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
qWarning() << FstName( fst ) << "is" << hex << fst.size << "bytes (" << clCnt << ") clusters";
|
qWarning() << FstName( fst ) << "is" << hex << fst.size << "bytes (" << clCnt << ") clusters";
|
||||||
hexdump( sp1 );
|
hexdump( sp1 );
|
||||||
hexdump( sp2 );
|
hexdump( sp2 );
|
||||||
@ -1960,7 +1846,7 @@ bool NandBin::CheckHmacMeta( quint16 clNo )
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
qWarning() << "supercluster" << hex << clNo;
|
qWarning() << "supercluster" << hex << clNo;
|
||||||
hexdump( sp1 );
|
hexdump( sp1 );
|
||||||
hexdump( sp2 );
|
hexdump( sp2 );
|
||||||
|
@ -16,7 +16,7 @@ Tmd::Tmd( const QByteArray &stuff )
|
|||||||
{
|
{
|
||||||
data.resize( SignedSize() );
|
data.resize( SignedSize() );
|
||||||
SetPointer();
|
SetPointer();
|
||||||
}
|
}
|
||||||
//hexdump( stuff );
|
//hexdump( stuff );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,11 @@ void Tmd::Dbg()
|
|||||||
QString s = QString( "TMD Dbg:\ntid:: %1\ncnt:: %2\n" )
|
QString s = QString( "TMD Dbg:\ntid:: %1\ncnt:: %2\n" )
|
||||||
.arg( Tid(), 16, 16, QChar( '0' ) )
|
.arg( Tid(), 16, 16, QChar( '0' ) )
|
||||||
.arg( cnt ) + contents;
|
.arg( cnt ) + contents;
|
||||||
qDebug() << s;
|
qDebug() << s;
|
||||||
|
quint8 *p = (quint8*)data.data();
|
||||||
|
qDebug() << "data" << p;
|
||||||
|
qDebug() << "pointer" << p_tmd;
|
||||||
|
qDebug() << "po" << payLoadOffset << SignedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tmd::FakeSign()
|
bool Tmd::FakeSign()
|
||||||
@ -243,16 +247,17 @@ bool Tmd::FakeSign()
|
|||||||
|
|
||||||
quint16 i = 0;
|
quint16 i = 0;
|
||||||
bool ret = false;//brute force the sha1
|
bool ret = false;//brute force the sha1
|
||||||
|
quint16 *fs = (quint16*)&p_tmd->reserved2;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
p_tmd->zero = i;//no need to worry about endian here
|
*fs = i;//no need to worry about endian here
|
||||||
if( GetSha1( data.mid( payLoadOffset, size ) ).startsWith( '\0' ) )
|
if( GetSha1( data.mid( payLoadOffset, size ) ).startsWith( '\0' ) )
|
||||||
{
|
{
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( ++i );
|
while( ++i );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +207,8 @@ Wad::Wad( QDir dir )
|
|||||||
//make sure to only add the tmd & ticket without all the cert mumbo jumbo
|
//make sure to only add the tmd & ticket without all the cert mumbo jumbo
|
||||||
tmdData = t.Data();
|
tmdData = t.Data();
|
||||||
tikData = ticket.Data();
|
tikData = ticket.Data();
|
||||||
|
t = Tmd( tmdData );
|
||||||
|
ticket = Ticket( tikData );
|
||||||
|
|
||||||
quint16 cnt = t.Count();
|
quint16 cnt = t.Count();
|
||||||
|
|
||||||
|
@ -548,7 +548,6 @@ bool CheckArm003( const QByteArray &stuff )
|
|||||||
qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check";
|
qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Check003()
|
void Check003()
|
||||||
|
Loading…
Reference in New Issue
Block a user