mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-12-24 03:51:49 +01:00
* moving the "library" files into a common folder 'WiiQt'
* adding in ASH0, LZ77 and ( messy ) U8 classes git-svn-id: http://wiiqt.googlecode.com/svn/trunk@12 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
parent
d8ea7b899b
commit
134bb8f277
429
WiiQt/ash.cpp
Normal file
429
WiiQt/ash.cpp
Normal file
@ -0,0 +1,429 @@
|
||||
#include "ash.h"
|
||||
bool IsAshCompressed( const QByteArray ba )
|
||||
{
|
||||
return ba.startsWith( "ASH" );
|
||||
}
|
||||
|
||||
QByteArray DecryptAsh( const QByteArray ba )
|
||||
{
|
||||
if( !IsAshCompressed( ba ) )
|
||||
{
|
||||
qWarning() << "DecryptAsh -> wrong magic";
|
||||
return QByteArray();
|
||||
}
|
||||
quint32 r[ 32 ];
|
||||
quint32 count=0;
|
||||
quint32 t;
|
||||
|
||||
quint64 memAddr = (quint64)( ba.data() );//in
|
||||
r[4] = 0x80000000;
|
||||
qint64 inDiff = memAddr - r[ 4 ];//difference in r[ 4 ] and the real address. hack to support higher memory addresses than crediar's version
|
||||
|
||||
r[5] = 0x415348;
|
||||
r[6] = 0x415348;
|
||||
|
||||
//Rvl_decode_ash:
|
||||
|
||||
r[5] = qFromBigEndian(*(quint32 *)( r[4] + inDiff + 4 ) );
|
||||
r[5] = r[5] & 0x00FFFFFF;
|
||||
|
||||
quint32 size = r[5];
|
||||
//qDebug() << "Decompressed size:" << hex << size;
|
||||
|
||||
char crap2[ size ];
|
||||
quint64 memAddr2 = (quint64)( crap2 );//outbuf
|
||||
r[3] = 0x90000000;
|
||||
qint64 outDiff = memAddr2 - r[ 3 ];//difference in r[ 3 ] and the real address
|
||||
|
||||
quint32 o = r[ 3 ];
|
||||
memset( (void*)( r[ 3 ] + outDiff ), 0, size );
|
||||
|
||||
r[24] = 0x10;
|
||||
r[28] = qFromBigEndian(*(quint32 *)(r[4]+8 + inDiff));
|
||||
r[25] = 0;
|
||||
r[29] = 0;
|
||||
r[26] = qFromBigEndian(*(quint32 *)(r[4]+0xC + inDiff));
|
||||
r[30] = qFromBigEndian(*(quint32 *)(r[4]+r[28] + inDiff));
|
||||
r[28] = r[28] + 4;
|
||||
//r[8] = 0x8108<<16;
|
||||
//HACK, pointer to RAM
|
||||
|
||||
char crap3[ 0x100000 ];
|
||||
quint64 memAddr3 = (quint64)( crap3 );//outbuf
|
||||
r[8] = 0x84000000;
|
||||
qint64 outDiff2 = memAddr3 - r[ 8 ];//difference in r[ 3 ] and the real address
|
||||
memset( (void*)( r[8] + outDiff2 ), 0, 0x100000 );
|
||||
|
||||
r[8] = r[8];
|
||||
r[9] = r[8] + 0x07FE;
|
||||
r[10] = r[9] + 0x07FE;
|
||||
r[11] = r[10] + 0x1FFE;
|
||||
r[31] = r[11] + 0x1FFE;
|
||||
r[23] = 0x200;
|
||||
r[22] = 0x200;
|
||||
r[27] = 0;
|
||||
|
||||
loc_81332124:
|
||||
|
||||
if( r[25] != 0x1F )
|
||||
goto loc_81332140;
|
||||
|
||||
r[0] = r[26] >> 31;
|
||||
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
|
||||
r[25]= 0;
|
||||
r[24]= r[24] + 4;
|
||||
goto loc_8133214C;
|
||||
|
||||
loc_81332140:
|
||||
|
||||
r[0] = r[26] >> 31;
|
||||
r[25]= r[25] + 1;
|
||||
r[26]= r[26] << 1;
|
||||
|
||||
loc_8133214C:
|
||||
|
||||
if( r[0] == 0 )
|
||||
goto loc_81332174;
|
||||
|
||||
r[0] = r[23] | 0x8000;
|
||||
*(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
|
||||
r[0] = r[23] | 0x4000;
|
||||
*(quint16 *)(r[31]+2 + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
|
||||
|
||||
r[31] = r[31] + 4;
|
||||
r[27] = r[27] + 2;
|
||||
r[23] = r[23] + 1;
|
||||
r[22] = r[22] + 1;
|
||||
|
||||
goto loc_81332124;
|
||||
|
||||
loc_81332174:
|
||||
|
||||
r[12] = 9;
|
||||
r[21] = r[25] + r[12];
|
||||
t = r[21];
|
||||
if( r[21] > 0x20 )
|
||||
goto loc_813321AC;
|
||||
|
||||
r[21] = (~(r[12] - 0x20))+1;
|
||||
r[6] = r[26] >> r[21];
|
||||
if( t == 0x20 )
|
||||
goto loc_8133219C;
|
||||
|
||||
r[26] = r[26] << r[12];
|
||||
r[25] = r[25] + r[12];
|
||||
goto loc_813321D0;
|
||||
|
||||
loc_8133219C:
|
||||
|
||||
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
|
||||
r[25]= 0;
|
||||
r[24]= r[24] + 4;
|
||||
goto loc_813321D0;
|
||||
|
||||
loc_813321AC:
|
||||
|
||||
r[0] = (~(r[12] - 0x20))+1;
|
||||
r[6] = r[26] >> r[0];
|
||||
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
|
||||
r[0] = (~(r[21] - 0x40))+1;
|
||||
r[24]= r[24] + 4;
|
||||
r[0] = r[26] >> r[0];
|
||||
r[6] = r[6] | r[0];
|
||||
r[25] = r[21] - 0x20;
|
||||
r[26] = r[26] << r[25];
|
||||
|
||||
loc_813321D0:
|
||||
|
||||
r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)(( r[31] + outDiff2 ) - 2)));
|
||||
r[31] -= 2;
|
||||
r[27]= r[27] - 1;
|
||||
r[0] = r[12] & 0x8000;
|
||||
r[12]= (r[12] & 0x1FFF) << 1;
|
||||
if( r[0] == 0 )
|
||||
goto loc_813321F8;
|
||||
|
||||
*(quint16 *)(r[9]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[6]);//?????
|
||||
r[6] = (r[12] & 0x3FFF)>>1;//extrwi %r6, %r12, 14,17
|
||||
if( r[27] != 0 )
|
||||
goto loc_813321D0;
|
||||
|
||||
goto loc_81332204;
|
||||
|
||||
loc_813321F8:
|
||||
|
||||
*(quint16 *)(r[8]+r[12] + outDiff2) = (quint16)qFromBigEndian((quint16)r[6]);
|
||||
r[23] = r[22];
|
||||
goto loc_81332124;
|
||||
|
||||
loc_81332204:
|
||||
|
||||
r[23] = 0x800;
|
||||
r[22] = 0x800;
|
||||
|
||||
loc_8133220C:
|
||||
|
||||
if( r[29] != 0x1F )
|
||||
goto loc_81332228;
|
||||
|
||||
r[0] = r[30] >> 31;
|
||||
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
|
||||
r[29]= 0;
|
||||
r[28]= r[28] + 4;
|
||||
goto loc_81332234;
|
||||
|
||||
loc_81332228:
|
||||
|
||||
r[0] = r[30] >> 31;
|
||||
r[29]= r[29] + 1;
|
||||
r[30]= r[30] << 1;
|
||||
|
||||
loc_81332234:
|
||||
|
||||
if( r[0] == 0 )
|
||||
goto loc_8133225C;
|
||||
|
||||
r[0] = r[23] | 0x8000;
|
||||
*(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
|
||||
r[0] = r[23] | 0x4000;
|
||||
*(quint16 *)(r[31]+2 + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
|
||||
|
||||
r[31] = r[31] + 4;
|
||||
r[27] = r[27] + 2;
|
||||
r[23] = r[23] + 1;
|
||||
r[22] = r[22] + 1;
|
||||
|
||||
goto loc_8133220C;
|
||||
|
||||
loc_8133225C:
|
||||
|
||||
r[12] = 0xB;
|
||||
r[21] = r[29] + r[12];
|
||||
t = r[21];
|
||||
if( r[21] > 0x20 )
|
||||
goto loc_81332294;
|
||||
|
||||
r[21] = (~(r[12] - 0x20))+1;
|
||||
r[7] = r[30] >> r[21];
|
||||
if( t == 0x20 )
|
||||
goto loc_81332284;
|
||||
|
||||
r[30] = r[30] << r[12];
|
||||
r[29] = r[29] + r[12];
|
||||
goto loc_813322B8;
|
||||
|
||||
loc_81332284:
|
||||
|
||||
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
|
||||
r[29]= 0;
|
||||
r[28]= r[28] + 4;
|
||||
goto loc_813322B8;
|
||||
|
||||
loc_81332294:
|
||||
|
||||
r[0] = (~(r[12] - 0x20))+1;
|
||||
r[7] = r[30] >> r[0];
|
||||
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
|
||||
r[0] = (~(r[21] - 0x40))+1;
|
||||
r[28]= r[28] + 4;
|
||||
r[0] = r[30] >> r[0];
|
||||
r[7] = r[7] | r[0];
|
||||
r[29]= r[21] - 0x20;
|
||||
r[30]= r[30] << r[29];
|
||||
|
||||
loc_813322B8:
|
||||
|
||||
r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)((r[31] + outDiff2 ) - 2)));
|
||||
r[31] -= 2;
|
||||
r[27]= r[27] - 1;
|
||||
r[0] = r[12] & 0x8000;
|
||||
r[12]= (r[12] & 0x1FFF) << 1;
|
||||
if( r[0] == 0 )
|
||||
goto loc_813322E0;
|
||||
|
||||
*(quint16 *)(r[11]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]);//????
|
||||
r[7] = (r[12] & 0x3FFF)>>1;// extrwi %r7, %r12, 14,17
|
||||
if( r[27] != 0 )
|
||||
goto loc_813322B8;
|
||||
|
||||
goto loc_813322EC;
|
||||
|
||||
loc_813322E0:
|
||||
|
||||
*(quint16 *)(r[10]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]);
|
||||
r[23] = r[22];
|
||||
goto loc_8133220C;
|
||||
|
||||
loc_813322EC:
|
||||
|
||||
r[0] = r[5];
|
||||
|
||||
loc_813322F0:
|
||||
|
||||
r[12]= r[6];
|
||||
|
||||
loc_813322F4:
|
||||
|
||||
if( r[12] < 0x200 )
|
||||
goto loc_8133233C;
|
||||
|
||||
if( r[25] != 0x1F )
|
||||
goto loc_81332318;
|
||||
|
||||
r[31] = r[26] >> 31;
|
||||
r[26] = qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
|
||||
r[24] = r[24] + 4;
|
||||
r[25] = 0;
|
||||
goto loc_81332324;
|
||||
|
||||
loc_81332318:
|
||||
|
||||
r[31] = r[26] >> 31;
|
||||
r[25] = r[25] + 1;
|
||||
r[26] = r[26] << 1;
|
||||
|
||||
loc_81332324:
|
||||
|
||||
r[27] = r[12] << 1;
|
||||
if( r[31] != 0 )
|
||||
goto loc_81332334;
|
||||
|
||||
r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[8] + r[27] + outDiff2 )));
|
||||
goto loc_813322F4;
|
||||
|
||||
loc_81332334:
|
||||
|
||||
r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[9] + r[27] + outDiff2 )));
|
||||
goto loc_813322F4;
|
||||
|
||||
loc_8133233C:
|
||||
|
||||
if( r[12] >= 0x100 )
|
||||
goto loc_8133235C;
|
||||
|
||||
*(quint8 *)(r[3] + outDiff) = r[12];
|
||||
r[3] = r[3] + 1;
|
||||
r[5] = r[5] - 1;
|
||||
if( r[5] != 0 )
|
||||
goto loc_813322F0;
|
||||
|
||||
goto loc_81332434;
|
||||
|
||||
loc_8133235C:
|
||||
|
||||
r[23] = r[7];
|
||||
|
||||
loc_81332360:
|
||||
|
||||
if( r[23] < 0x800 )
|
||||
goto loc_813323A8;
|
||||
|
||||
if( r[29] != 0x1F )
|
||||
goto loc_81332384;
|
||||
|
||||
r[31] = r[30] >> 31;
|
||||
r[30] = qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
|
||||
r[28] = r[28] + 4;
|
||||
r[29] = 0;
|
||||
goto loc_81332390;
|
||||
|
||||
loc_81332384:
|
||||
|
||||
r[31] = r[30] >> 31;
|
||||
r[29] = r[29] + 1;
|
||||
r[30] = r[30] << 1;
|
||||
|
||||
loc_81332390:
|
||||
|
||||
r[27] = r[23] << 1;
|
||||
if( r[31] != 0 )
|
||||
goto loc_813323A0;
|
||||
|
||||
r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[10] + r[27] + outDiff2 )));
|
||||
goto loc_81332360;
|
||||
|
||||
loc_813323A0:
|
||||
|
||||
r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[11] + r[27] + outDiff2 )));
|
||||
goto loc_81332360;
|
||||
|
||||
loc_813323A8:
|
||||
|
||||
r[12] = r[12] - 0xFD;
|
||||
r[23] = ~r[23] + r[3] + 1;
|
||||
r[5] = ~r[12] + r[5] + 1;
|
||||
r[31] = r[12] >> 3;
|
||||
|
||||
if( r[31] == 0 )
|
||||
goto loc_81332414;
|
||||
|
||||
count = r[31];
|
||||
|
||||
loc_813323C0:
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) - 1);
|
||||
*(quint8 *)(r[3] + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)( r[23] + outDiff );
|
||||
*(quint8 *)(r[3]+1 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 1);
|
||||
*(quint8 *)(r[3]+2 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 2);
|
||||
*(quint8 *)(r[3]+3 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 3);
|
||||
*(quint8 *)(r[3]+4 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 4);
|
||||
*(quint8 *)(r[3]+5 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 5);
|
||||
*(quint8 *)(r[3]+6 + outDiff) = r[31];
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) + 6);
|
||||
*(quint8 *)(r[3]+7 + outDiff) = r[31];
|
||||
|
||||
r[23] = r[23] + 8;
|
||||
r[3] = r[3] + 8;
|
||||
|
||||
if( --count )
|
||||
goto loc_813323C0;
|
||||
|
||||
r[12] = r[12] & 7;
|
||||
if( r[12] == 0 )
|
||||
goto loc_8133242C;
|
||||
|
||||
loc_81332414:
|
||||
|
||||
count = r[12];
|
||||
|
||||
loc_81332418:
|
||||
|
||||
r[31] = *(quint8 *)(( r[23] + outDiff ) - 1);
|
||||
r[23] = r[23] + 1;
|
||||
*(quint8 *)(r[3] + outDiff ) = r[31];
|
||||
r[3] = r[3] + 1;
|
||||
|
||||
if( --count )
|
||||
goto loc_81332418;
|
||||
|
||||
loc_8133242C:
|
||||
|
||||
if( r[5] != 0 )
|
||||
goto loc_813322F0;
|
||||
|
||||
loc_81332434:
|
||||
|
||||
r[3] = r[0];
|
||||
|
||||
QByteArray ret( r[ 3 ], '\0' );
|
||||
QBuffer outBuf( &ret );
|
||||
outBuf.open( QIODevice::WriteOnly );
|
||||
outBuf.write( (const char*)( o + outDiff ), r[ 3 ] );
|
||||
outBuf.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
13
WiiQt/ash.h
Normal file
13
WiiQt/ash.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef ASH_H
|
||||
#define ASH_H
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
//returns a byteArray of decompressed ASH data
|
||||
//returns an empty array if the data doesnt have the ASH magic word
|
||||
QByteArray DecryptAsh( const QByteArray ba );
|
||||
|
||||
//check if data starts with "ASH". no other check is done
|
||||
bool IsAshCompressed( const QByteArray ba );
|
||||
|
||||
#endif // ASH_H
|
@ -15,8 +15,8 @@
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
//#include <QNetworkAccessManager>
|
||||
//#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QQueue>
|
393
WiiQt/lz77.cpp
Normal file
393
WiiQt/lz77.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
#include "lz77.h"
|
||||
|
||||
//most functions here are taken from wii.cs by leathl
|
||||
//they have just been tweeked slightly to work with Qt C++
|
||||
|
||||
LZ77::LZ77()
|
||||
{
|
||||
match_position = 0;
|
||||
match_length = 0;
|
||||
textsize = 0;
|
||||
codesize = 0;
|
||||
}
|
||||
|
||||
int LZ77::GetLz77Offset( const QByteArray &data )
|
||||
{
|
||||
QByteArray start = data.left( 5000 );
|
||||
|
||||
return start.indexOf( "LZ77" );
|
||||
}
|
||||
|
||||
void LZ77::InitTree()
|
||||
{
|
||||
int i;
|
||||
int N = 4096;
|
||||
for( i = N + 1; i <= N + 256; i++ )
|
||||
rson[ i ] = N;
|
||||
|
||||
for( i = 0; i < N; i++ )
|
||||
dad[ i ] = N;
|
||||
}
|
||||
|
||||
void LZ77::DeleteNode( int p )
|
||||
{
|
||||
int N = 4096;
|
||||
int q;
|
||||
|
||||
if( dad[ p ] == N )
|
||||
return; /* not in tree */
|
||||
|
||||
if( rson[ p ] == N )
|
||||
q = lson[ p ];
|
||||
|
||||
else if( lson[ p ] == N )
|
||||
q = rson[ p ];
|
||||
|
||||
else
|
||||
{
|
||||
q = lson[ p ];
|
||||
|
||||
if( rson[ q ] != N )
|
||||
{
|
||||
do
|
||||
{
|
||||
q = rson[ q ];
|
||||
}
|
||||
while( rson[ q ] != N );
|
||||
|
||||
rson[ dad[ q ] ] = lson[ q ];
|
||||
dad[ lson[ q ] ] = dad[ q ];
|
||||
|
||||
lson[ q ] = lson[ p ];
|
||||
dad[ lson[ p ] ] = q;
|
||||
}
|
||||
rson[ q ] = rson[ p ];
|
||||
dad[ rson[ p ] ] = q;
|
||||
}
|
||||
dad[ q ] = dad[ p ];
|
||||
|
||||
if( rson[ dad[ p ] ] == p )
|
||||
rson[ dad[ p ] ] = q;
|
||||
else
|
||||
lson[ dad[ p ] ] = q;
|
||||
|
||||
dad[ p ] = N;
|
||||
}
|
||||
|
||||
void LZ77::InsertNode( int r )
|
||||
{
|
||||
int i, p, cmp;
|
||||
int N = 4096;
|
||||
int F = 18;
|
||||
cmp = 1;
|
||||
p = N + 1 + ( text_buf[ r ] == ( quint16 )0xffff ? ( quint16 )0 : text_buf[ r ] );
|
||||
rson[ r ] = lson[ r ] = N;
|
||||
match_length = 0;
|
||||
for( ; ; )
|
||||
{
|
||||
if( cmp >= 0 )
|
||||
{
|
||||
if( rson[ p ] != N )
|
||||
p = rson[ p ];
|
||||
else
|
||||
{
|
||||
rson[ p ] = r;
|
||||
dad[ r ] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( lson[ p ] != N )
|
||||
p = lson[ p ];
|
||||
|
||||
else
|
||||
{
|
||||
lson[ p ] = r;
|
||||
dad[ r ] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for( i = 1; i < F; i++ )
|
||||
if( ( cmp = text_buf[ r + i ] - text_buf[ p + i ] ) != 0 )
|
||||
break;
|
||||
if( i > match_length )
|
||||
{
|
||||
match_position = p;
|
||||
if( ( match_length = i ) >= F )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dad[ r ] = dad[ p ];
|
||||
lson[ r ] = lson[ p ];
|
||||
rson[ r ] = rson[ p ];
|
||||
dad[ lson[ p ] ] = r;
|
||||
dad[ rson[ p ] ] = r;
|
||||
|
||||
if( rson[ dad[ p ] ] == p )
|
||||
rson[ dad[ p ] ] = r;
|
||||
|
||||
else
|
||||
lson[ dad[ p ] ] = r;
|
||||
|
||||
dad[ p ] = N;
|
||||
}
|
||||
|
||||
quint32 LZ77::GetDecompressedSize( const QByteArray &data )
|
||||
{
|
||||
int off = GetLz77Offset( data );
|
||||
if( off == -1 )
|
||||
{
|
||||
qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic";
|
||||
return 0;
|
||||
}
|
||||
QByteArray ba = data;
|
||||
QBuffer buf( &ba );
|
||||
if( !buf.open( QBuffer::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "LZ77::GetDecompressedSize -> Can't create buffer";
|
||||
return 0;
|
||||
}
|
||||
buf.seek( off + 4 );
|
||||
|
||||
quint32 gbaheader;
|
||||
buf.seek( off + 4 );
|
||||
buf.read( (char*)&gbaheader, 4 );
|
||||
|
||||
return ( gbaheader >> 8 );
|
||||
}
|
||||
|
||||
QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
|
||||
{
|
||||
int N = 4096;
|
||||
int F = 18;
|
||||
int threshold = 2;
|
||||
int k, r, z, flags;
|
||||
quint16 i, j;
|
||||
char ch;
|
||||
quint32 decomp_size;
|
||||
quint32 cur_size = 0;
|
||||
|
||||
QByteArray crap = compressed;
|
||||
QBuffer infile( &crap );
|
||||
if( !infile.open( QBuffer::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "Can't create buffer 1";
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray ret;
|
||||
QBuffer outfile( &ret );
|
||||
if( !outfile.open( QBuffer::ReadWrite ) )
|
||||
{
|
||||
qWarning() << "Can't create buffer 2";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
quint32 gbaheader;
|
||||
infile.seek( offset + 4 );
|
||||
infile.read( (char*)&gbaheader, 4 );
|
||||
|
||||
decomp_size = gbaheader >> 8;
|
||||
quint8 text_buf[ N + 17 ];
|
||||
|
||||
for( i = 0; i < N - F; i++ )
|
||||
text_buf[ i ] = 0xdf;
|
||||
|
||||
r = N - F;
|
||||
flags = 7;
|
||||
z = 7;
|
||||
|
||||
while( true )
|
||||
{
|
||||
flags <<= 1;
|
||||
z++;
|
||||
if( z == 8 )
|
||||
{
|
||||
if( !infile.getChar( &ch ) )
|
||||
break;
|
||||
flags = (quint8) ch;
|
||||
z = 0;
|
||||
}
|
||||
if( ( flags & 0x80 ) == 0 )
|
||||
{
|
||||
if( !infile.getChar( &ch ) )
|
||||
break;
|
||||
|
||||
if( cur_size < decomp_size )
|
||||
outfile.putChar( ch );
|
||||
|
||||
text_buf[ r++ ] = ch;
|
||||
r &= ( N - 1 );
|
||||
cur_size++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !infile.getChar( &ch ) )
|
||||
break;
|
||||
i = (quint8)ch;
|
||||
|
||||
if( !infile.getChar( &ch ) )
|
||||
break;
|
||||
j = (quint8)ch;
|
||||
|
||||
j = j | ( (i << 8) & 0xf00 );
|
||||
i = ( ( i >> 4 ) & 0x0f ) + threshold;
|
||||
|
||||
for( k = 0; k <= i; k++ )
|
||||
{
|
||||
ch = text_buf[ ( r - j - 1 ) & ( N - 1 ) ];
|
||||
if( cur_size < decomp_size )
|
||||
outfile.putChar( ch );
|
||||
|
||||
text_buf[ r++ ] = ch;
|
||||
r &= ( N - 1 );
|
||||
cur_size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QByteArray LZ77::Decompress( const QByteArray &compressed )
|
||||
{
|
||||
int off = GetLz77Offset( compressed );
|
||||
if( off < 0 )
|
||||
{
|
||||
qWarning() << "LZ77::Decompress -> data is not compressed";
|
||||
return compressed;
|
||||
}
|
||||
return Decompress( compressed, off );
|
||||
}
|
||||
|
||||
QByteArray LZ77::Compress( const QByteArray &ba )
|
||||
{
|
||||
//testing 1, 2
|
||||
//return ba;
|
||||
LZ77 lz;
|
||||
QByteArray ret = lz.Compr( ba );
|
||||
return ret;
|
||||
}
|
||||
|
||||
QByteArray LZ77::Compr( const QByteArray &ba )
|
||||
{
|
||||
int i, len, r, s, last_match_length, code_buf_ptr;
|
||||
char ch;
|
||||
int code_buf[ 17 ];
|
||||
int mask;
|
||||
int N = 4096;
|
||||
int F = 18;
|
||||
int threshold = 2;
|
||||
quint32 filesize = (ba.size() << 8) + 0x10;
|
||||
|
||||
QByteArray crap = ba;
|
||||
QBuffer infile( &crap );
|
||||
if( !infile.open( QBuffer::ReadOnly ) )
|
||||
{
|
||||
qWarning() << "Can't create buffer 1";
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray ret;
|
||||
QBuffer output( &ret );
|
||||
if( !output.open( QBuffer::ReadWrite ) )
|
||||
{
|
||||
qWarning() << "Can't create buffer 2";
|
||||
return QByteArray();
|
||||
}
|
||||
output.putChar( 'L' );
|
||||
output.putChar( 'Z' );
|
||||
output.putChar( '7' );
|
||||
output.putChar( '7' );
|
||||
|
||||
output.write( (const char*)&filesize, 4 );
|
||||
|
||||
InitTree();
|
||||
code_buf[ 0 ] = 0;
|
||||
code_buf_ptr = 1;
|
||||
mask = 0x80;
|
||||
s = 0;
|
||||
r = N - F;
|
||||
|
||||
for( i = s; i < r; i++ )
|
||||
text_buf[ i ] = 0xffff;
|
||||
|
||||
for( len = 0; len < F && infile.getChar( &ch ); len++ )
|
||||
text_buf[ r + len ] = (quint8)ch;
|
||||
|
||||
if( ( textsize = len ) == 0)
|
||||
return ba;
|
||||
|
||||
for( i = 1; i <= F; i++ )
|
||||
InsertNode( r - i );
|
||||
|
||||
InsertNode( r );
|
||||
|
||||
do
|
||||
{
|
||||
if( match_length > len )
|
||||
match_length = len;
|
||||
|
||||
if( match_length <= threshold )
|
||||
{
|
||||
match_length = 1;
|
||||
code_buf[ code_buf_ptr++ ] = text_buf[ r ];
|
||||
}
|
||||
else
|
||||
{
|
||||
code_buf[ 0 ] |= mask;
|
||||
|
||||
code_buf[ code_buf_ptr++ ] = (quint8)
|
||||
( ( ( r - match_position - 1 ) >> 8) & 0x0f ) |
|
||||
( ( match_length - ( threshold + 1 ) ) << 4 );
|
||||
|
||||
code_buf[ code_buf_ptr++ ] = (quint8)( ( r - match_position - 1 ) & 0xff );
|
||||
}
|
||||
if( ( mask >>= 1 ) == 0 )
|
||||
{
|
||||
for( i = 0; i < code_buf_ptr; i++ )
|
||||
output.putChar( (quint8)code_buf[ i ] );
|
||||
|
||||
codesize += code_buf_ptr;
|
||||
code_buf[ 0 ] = 0; code_buf_ptr = 1;
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
last_match_length = match_length;
|
||||
for( i = 0; i < last_match_length && infile.getChar( &ch ); i++ )
|
||||
{
|
||||
DeleteNode( s );
|
||||
text_buf[ s ] = (quint8)ch;
|
||||
if( s < F - 1 )
|
||||
text_buf[ s + N ] = (quint8)ch;
|
||||
|
||||
s = ( s + 1 ) & ( N - 1 );
|
||||
r = ( r + 1 ) & ( N - 1 );
|
||||
InsertNode( r );
|
||||
}
|
||||
|
||||
while( i++ < last_match_length )
|
||||
{
|
||||
DeleteNode( s );
|
||||
s = ( s + 1 ) & ( N - 1 );
|
||||
r = ( r + 1 ) & ( N - 1 );
|
||||
if( --len != 0 )
|
||||
InsertNode( r );
|
||||
}
|
||||
}
|
||||
while( len > 0 );
|
||||
|
||||
if( code_buf_ptr > 1 )
|
||||
{
|
||||
for( i = 0; i < code_buf_ptr; i++ )
|
||||
output.putChar( (quint8)code_buf[ i ] );
|
||||
|
||||
codesize += code_buf_ptr;
|
||||
}
|
||||
int padding = codesize % 4;
|
||||
if( padding != 0 )
|
||||
output.write( QByteArray( 4 - padding, '\0' ) );
|
||||
|
||||
infile.close();
|
||||
return ret;
|
||||
}
|
48
WiiQt/lz77.h
Normal file
48
WiiQt/lz77.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef LZ77_H
|
||||
#define LZ77_H
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
//class for daling with LZ77 compression
|
||||
//! in most cases, you just want to use the static functions
|
||||
// QByteArray stuff = LZ77::Decompress( someCompressedData );
|
||||
// QByteArray compressedData = LZ77::Compress( someData );
|
||||
class LZ77
|
||||
{
|
||||
public:
|
||||
LZ77();
|
||||
void InsertNode( int r );
|
||||
void DeleteNode( int p );
|
||||
void InitTree();
|
||||
|
||||
//gets the offset in a bytearray if the lz77 magic word
|
||||
static int GetLz77Offset( const QByteArray &data );
|
||||
|
||||
//gets the decompressed size of a lz77 compressed buffer
|
||||
static quint32 GetDecompressedSize( const QByteArray &data );
|
||||
|
||||
//used internally by the static compression function
|
||||
QByteArray Compr( const QByteArray &ba );
|
||||
|
||||
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 );
|
||||
|
||||
//compressed a qbytearray with the lz77 argorythm
|
||||
//returns a qbytearray ncluding the lz77 header
|
||||
static QByteArray Compress( const QByteArray &ba );
|
||||
|
||||
private:
|
||||
int lson[ 4097 ];
|
||||
int rson[ 4353 ];
|
||||
int dad[ 4097 ];
|
||||
quint16 text_buf[ 4113 ];
|
||||
int match_position;
|
||||
int match_length;
|
||||
int textsize;
|
||||
int codesize;
|
||||
};
|
||||
|
||||
#endif // LZ77_H
|
377
WiiQt/md5.cpp
Normal file
377
WiiQt/md5.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
/* MD5
|
||||
converted to C++ class by Frank Thilo (thilo@unix-ag.org)
|
||||
for bzflag (http://www.bzflag.org)
|
||||
|
||||
based on:
|
||||
|
||||
md5.h and md5.c
|
||||
reference implemantion of RFC 1321
|
||||
|
||||
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
|
||||
*/
|
||||
|
||||
/* interface header */
|
||||
#include "md5.h"
|
||||
|
||||
/* system implementation headers */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// Constants for MD5Transform routine.
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
//char output[50];
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// F, G, H and I are basic MD5 functions.
|
||||
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
|
||||
return (x&y) | (~x&z);
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
|
||||
return (x&z) | (y&~z);
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
|
||||
return x^y^z;
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
|
||||
return y ^ (x | ~z);
|
||||
}
|
||||
|
||||
// rotate_left rotates x left n bits.
|
||||
inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
|
||||
return (x << n) | (x >> (32-n));
|
||||
}
|
||||
|
||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
// Rotation is separate from addition to prevent recomputation.
|
||||
inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a+ F(b,c,d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + G(b,c,d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + H(b,c,d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + I(b,c,d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
// default ctor, just initailize
|
||||
MD5::MD5()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
// nifty shortcut ctor, compute MD5 for string and finalize it right away
|
||||
MD5::MD5(const std::string &text)
|
||||
{
|
||||
init();
|
||||
update(text.c_str(), text.length());
|
||||
finalize();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
void MD5::init()
|
||||
{
|
||||
finalized=false;
|
||||
|
||||
count[0] = 0;
|
||||
count[1] = 0;
|
||||
|
||||
// load magic initialization constants.
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
|
||||
void MD5::decode(uint4 output[], const uint1 input[], size_type len)
|
||||
{
|
||||
for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
|
||||
(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// encodes input (uint4) into output (unsigned char). Assumes len is
|
||||
// a multiple of 4.
|
||||
void MD5::encode(uint1 output[], const uint4 input[], size_type len)
|
||||
{
|
||||
for (size_type i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = input[i] & 0xff;
|
||||
output[j+1] = (input[i] >> 8) & 0xff;
|
||||
output[j+2] = (input[i] >> 16) & 0xff;
|
||||
output[j+3] = (input[i] >> 24) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// apply MD5 algo on a block
|
||||
void MD5::transform(const uint1 block[blocksize])
|
||||
{
|
||||
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
decode (x, block, blocksize);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset(x, 0, sizeof x);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// MD5 block update operation. Continues an MD5 message-digest
|
||||
// operation, processing another message block
|
||||
void MD5::update(const unsigned char input[], size_type length)
|
||||
{
|
||||
// compute number of bytes mod 64
|
||||
size_type index = count[0] / 8 % blocksize;
|
||||
|
||||
// Update number of bits
|
||||
if ((count[0] += (length << 3)) < (length << 3))
|
||||
count[1]++;
|
||||
count[1] += (length >> 29);
|
||||
|
||||
// number of bytes we need to fill in buffer
|
||||
size_type firstpart = 64 - index;
|
||||
|
||||
size_type i;
|
||||
|
||||
// transform as many times as possible.
|
||||
if (length >= firstpart)
|
||||
{
|
||||
// fill buffer first, transform
|
||||
memcpy(&buffer[index], input, firstpart);
|
||||
transform(buffer);
|
||||
|
||||
// transform chunks of blocksize (64 bytes)
|
||||
for (i = firstpart; i + blocksize <= length; i += blocksize)
|
||||
transform(&input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
// buffer remaining input
|
||||
memcpy(&buffer[index], &input[i], length-i);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// for convenience provide a verson with signed char
|
||||
void MD5::update(const char input[], size_type length)
|
||||
{
|
||||
update((const unsigned char*)input, length);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
// the message digest and zeroizing the context.
|
||||
MD5& MD5::finalize()
|
||||
{
|
||||
static unsigned char padding[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
if (!finalized) {
|
||||
// Save number of bits
|
||||
unsigned char bits[8];
|
||||
encode(bits, count, 8);
|
||||
|
||||
// pad out to 56 mod 64.
|
||||
size_type index = count[0] / 8 % 64;
|
||||
size_type padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
update(padding, padLen);
|
||||
|
||||
// Append length (before padding)
|
||||
update(bits, 8);
|
||||
|
||||
// Store state in digest
|
||||
encode(digest, state, 16);
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
memset(count, 0, sizeof count);
|
||||
|
||||
finalized=true;
|
||||
}
|
||||
//sprintf(output,"%s",this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
// return hex representation of digest as string
|
||||
std::string MD5::hexdigest() const
|
||||
{
|
||||
if (!finalized)
|
||||
return "";
|
||||
|
||||
char buf[33];
|
||||
for (int i=0; i<16; i++)
|
||||
sprintf(buf+i*2, "%02x", digest[i]);
|
||||
buf[32]=0;
|
||||
|
||||
sprintf( (char*)outputBuf,"%s",buf);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
char* MD5::hexdigestChar() const
|
||||
{
|
||||
if (!finalized)
|
||||
return NULL;
|
||||
|
||||
memset( (char*)&outputBuf, 0, 0x20 );
|
||||
memcpy( (char*)&outputBuf, &digest, 16 );
|
||||
return (char*)outputBuf;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, MD5 md5)
|
||||
{
|
||||
return out << md5.hexdigest();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
std::string md5(const std::string str)
|
||||
{
|
||||
MD5 md5 = MD5(str);
|
||||
|
||||
return md5.hexdigest();
|
||||
}
|
||||
|
99
WiiQt/md5.h
Normal file
99
WiiQt/md5.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* MD5
|
||||
converted to C++ class by Frank Thilo (thilo@unix-ag.org)
|
||||
for bzflag (http://www.bzflag.org)
|
||||
|
||||
based on:
|
||||
|
||||
md5.h and md5.c
|
||||
reference implementation of RFC 1321
|
||||
|
||||
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BZF_MD5_H
|
||||
#define BZF_MD5_H
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
// a small class for calculating MD5 hashes of strings or byte arrays
|
||||
// it is not meant to be fast or secure
|
||||
//
|
||||
// usage: 1) feed it blocks of uchars with update()
|
||||
// 2) finalize()
|
||||
// 3) get hexdigest() string
|
||||
// or
|
||||
// MD5(std::string).hexdigest()
|
||||
//
|
||||
// assumes that char is 8 bit and int is 32 bit
|
||||
class MD5
|
||||
{
|
||||
public:
|
||||
typedef unsigned int size_type; // must be 32bit
|
||||
|
||||
MD5();
|
||||
MD5(const std::string& text);
|
||||
void update(const unsigned char *buf, size_type length);
|
||||
void update(const char *buf, size_type length);
|
||||
MD5& finalize();
|
||||
std::string hexdigest() const;
|
||||
char* hexdigestChar() const;
|
||||
friend std::ostream& operator<<(std::ostream&, MD5 md5);
|
||||
|
||||
private:
|
||||
void init();
|
||||
typedef unsigned char uint1; // 8bit
|
||||
typedef unsigned int uint4; // 32bit
|
||||
enum {blocksize = 64}; // VC6 won't eat a const static int here
|
||||
|
||||
void transform(const uint1 block[blocksize]);
|
||||
static void decode(uint4 output[], const uint1 input[], size_type len);
|
||||
static void encode(uint1 output[], const uint4 input[], size_type len);
|
||||
|
||||
bool finalized;
|
||||
uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
|
||||
uint4 count[2]; // 64bit counter for number of bits (lo, hi)
|
||||
uint4 state[4]; // digest so far
|
||||
uint1 digest[16]; // the result
|
||||
|
||||
// low level logic operations
|
||||
static inline uint4 F(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 G(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 H(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 I(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 rotate_left(uint4 x, int n);
|
||||
static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
|
||||
//little buffer for giving the result
|
||||
char outputBuf[ 0x20 ];
|
||||
};
|
||||
|
||||
std::string md5(const std::string str);
|
||||
|
||||
#endif
|
||||
|
@ -22,8 +22,7 @@ NandBin::~NandBin()
|
||||
|
||||
bool NandBin::SetPath( const QString &path )
|
||||
{
|
||||
nandPath = path;//TODO: dont need both these variables. definitely dont need to set the global one here
|
||||
nandFile = path;
|
||||
//nandPath = path;
|
||||
if( f.isOpen() )
|
||||
f.close();
|
||||
|
||||
@ -246,7 +245,7 @@ bool NandBin::GetKey( int type )
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
QString keyPath = nandFile;
|
||||
QString keyPath = nandPath;
|
||||
int sl = keyPath.lastIndexOf( "/" );
|
||||
if( sl == -1 )
|
||||
{
|
||||
@ -514,6 +513,72 @@ void NandBin::SetFixNamesForFAT( bool fix )
|
||||
fatNames = fix;
|
||||
}
|
||||
|
||||
const QByteArray NandBin::GetData( const QString &path )
|
||||
{
|
||||
QTreeWidgetItem *item = ItemFromPath( path );
|
||||
if( !item )
|
||||
return QByteArray();
|
||||
|
||||
if( !item->text( 6 ).contains( "1" ) )
|
||||
{
|
||||
qDebug() << "NandBin::GetData -> can't get data for a folder" << item->text( 0 );
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
quint16 entry = item->text( 1 ).toInt( &ok, 10 );
|
||||
if( !ok )
|
||||
return QByteArray();
|
||||
|
||||
return GetFile( entry );
|
||||
}
|
||||
|
||||
QTreeWidgetItem *NandBin::ItemFromPath( const QString &path )
|
||||
{
|
||||
if( !root || !root->childCount() )
|
||||
return NULL;
|
||||
|
||||
QTreeWidgetItem *item = root->child( 0 );
|
||||
if( item->text( 0 ) != "/" )
|
||||
{
|
||||
qWarning() << "NandBin::ItemFromPath -> root is not \"/\"" << item->text( 0 );
|
||||
return NULL;
|
||||
}
|
||||
if( !path.startsWith( "/" ) || path.contains( "//" ))
|
||||
{
|
||||
qWarning() << "NandBin::ItemFromPath -> invalid path";
|
||||
return NULL;
|
||||
}
|
||||
int slash = 1;
|
||||
while( slash )
|
||||
{
|
||||
int nextSlash = path.indexOf( "/", slash + 1 );
|
||||
QString lookingFor = path.mid( slash, nextSlash - slash );
|
||||
item = FindItem( lookingFor, item );
|
||||
if( !item )
|
||||
{
|
||||
qWarning() << "NandBin::ItemFromPath ->item not found" << path;
|
||||
return NULL;
|
||||
}
|
||||
slash = nextSlash + 1;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
QTreeWidgetItem *NandBin::FindItem( const QString &s, QTreeWidgetItem *parent )
|
||||
{
|
||||
int cnt = parent->childCount();
|
||||
for( int i = 0; i <cnt; i++ )
|
||||
{
|
||||
QTreeWidgetItem *r = parent->child( i );
|
||||
if( r->text( 0 ) == s )
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NandBin::ShowInfo()
|
||||
{
|
||||
quint16 badBlocks = 0;
|
@ -4,7 +4,7 @@
|
||||
#include "includes.h"
|
||||
struct fst_t
|
||||
{
|
||||
quint8 filename[ 0xc ];//showmii wads has size 0xb here but reads 0xc bytes into name??
|
||||
quint8 filename[ 0xc ];
|
||||
quint8 mode;
|
||||
quint8 attr;
|
||||
quint16 sub;
|
||||
@ -17,25 +17,42 @@ struct fst_t
|
||||
// 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()
|
||||
// extract files with GetFile()
|
||||
|
||||
//once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree()
|
||||
class NandBin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//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() );
|
||||
|
||||
//destroys this object, and all its used resources ( closes the nand.bin file and deletes the filetree )
|
||||
~NandBin();
|
||||
|
||||
//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
|
||||
bool SetPath( const QString &path );
|
||||
|
||||
//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
|
||||
//icons given here will be the ones used when asking for that tree
|
||||
bool InitNand( QIcon dirs = QIcon(), QIcon files = QIcon() );
|
||||
|
||||
//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
|
||||
//! all returned items are cloned and it is up to you to delete them !
|
||||
//text is assigned to the items as follows...
|
||||
// 0 name
|
||||
// 1 entry #
|
||||
// 2 size
|
||||
// 3 uid
|
||||
// 4 gid
|
||||
// 5 x3
|
||||
// 6 mode
|
||||
// 7 attr
|
||||
QTreeWidgetItem *GetTree();
|
||||
|
||||
//returns the data that makes up the file of a given entry#
|
||||
QByteArray GetFile( quint16 entry );
|
||||
|
||||
//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
|
||||
@ -48,13 +65,27 @@ public:
|
||||
//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 );
|
||||
|
||||
//returns the data that makes up the file of a given entry#
|
||||
QByteArray GetFile( quint16 entry );
|
||||
|
||||
|
||||
//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
|
||||
//! and then end up calling the above one anyways.
|
||||
//the path should be a file, not folder
|
||||
//returns an empty array on failure
|
||||
//path should start with "/" and items should be delimited by "/"
|
||||
//ie... /title/00000001/00000002/data/setting.txt
|
||||
const QByteArray GetData( const QString &path );
|
||||
|
||||
|
||||
private:
|
||||
QByteArray key;
|
||||
qint32 loc_super;
|
||||
qint32 loc_fat;
|
||||
qint32 loc_fst;
|
||||
QString extractPath;
|
||||
QString nandFile;
|
||||
QString nandPath;
|
||||
QFile f;
|
||||
int type;
|
||||
|
||||
@ -69,7 +100,6 @@ private:
|
||||
quint16 GetFAT( quint16 fat_entry );
|
||||
fst_t GetFST( quint16 entry );
|
||||
QByteArray GetCluster( quint16 cluster_entry, bool decrypt = true );
|
||||
//QByteArray ReadPage( quint32 i, bool withEcc = false );
|
||||
QByteArray GetFile( fst_t fst );
|
||||
|
||||
QString FstName( fst_t fst );
|
||||
@ -81,8 +111,11 @@ private:
|
||||
|
||||
QTreeWidgetItem *root;
|
||||
bool AddChildren( QTreeWidgetItem *parent, quint16 entry );
|
||||
QTreeWidgetItem *ItemFromPath( const QString &path );
|
||||
QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent );
|
||||
|
||||
signals:
|
||||
//connect to these to receive messages from this object
|
||||
void SendError( QString );
|
||||
void SendText( QString );
|
||||
};
|
@ -126,6 +126,8 @@ QByteArray NandDump::GetSettingTxt()
|
||||
|
||||
bool NandDump::SetSettingTxt( const QByteArray ba )
|
||||
{
|
||||
if( basePath.isEmpty() )
|
||||
return false;
|
||||
QString path = basePath + "/title/00000001/00000002/data";
|
||||
if( !QFileInfo( path ).exists() && !QDir().mkpath( path ) )
|
||||
return false;
|
||||
@ -134,6 +136,8 @@ bool NandDump::SetSettingTxt( const QByteArray ba )
|
||||
|
||||
const QByteArray NandDump::GetFile( const QString &path )
|
||||
{
|
||||
if( basePath.isEmpty() )
|
||||
return QByteArray();
|
||||
QFile f( basePath + path );
|
||||
if( !f.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
@ -148,6 +152,8 @@ const QByteArray NandDump::GetFile( const QString &path )
|
||||
//write some file to the nand
|
||||
bool NandDump::SaveData( const QByteArray ba, const QString& path )
|
||||
{
|
||||
if( basePath.isEmpty() )
|
||||
return false;
|
||||
qDebug() << "NandDump::SaveData" << path << hex << ba.size();
|
||||
QFile f( basePath + path );
|
||||
if( !f.open( QIODevice::WriteOnly ) )
|
||||
@ -164,6 +170,8 @@ bool NandDump::SaveData( const QByteArray ba, const QString& path )
|
||||
void NandDump::DeleteData( const QString & path )
|
||||
{
|
||||
qDebug() << "NandDump::DeleteData" << path;
|
||||
if( basePath.isEmpty() )
|
||||
return;
|
||||
QFile::remove( basePath + path );
|
||||
}
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include "sharedcontentmap.h"
|
||||
#include "uidmap.h"
|
||||
|
||||
//class for handeling an extracted wii nand filesystem
|
||||
//! nothing can be done unless basePath is set. do this either by setting it in the constructor, or by calling SetPath()
|
||||
//! current reading and writing is limited to installing a title in the form of NusJob, reading/writing/deleting specific paths
|
||||
//! for performance reasons, the uid and content map are cached and only written to the HDD when the destructor or Flush() is called
|
||||
class NandDump
|
||||
{
|
||||
public:
|
||||
@ -27,17 +31,27 @@ public:
|
||||
bool DeleteTitle( quint64 tid, bool deleteData = false );
|
||||
|
||||
//check what version a given title is on this nand, returns 0 if it isnt installed
|
||||
quint16 GetTitleVersion( quint64 tid );
|
||||
//quint16 GetTitleVersion( quint64 tid );
|
||||
|
||||
//get a list of all titles for which there is a ticket & tmd
|
||||
// returns a map of < tid, version >
|
||||
//QMap< quint64, quint16 > GetInstalledTitles();
|
||||
|
||||
//write the current uid & content.map to the PC
|
||||
//failure to make sure this is done can end up with a broken nand
|
||||
bool Flush();
|
||||
|
||||
//overloads GetFile() with "/title/00000001/00000002/data/setting.txt"
|
||||
QByteArray GetSettingTxt();
|
||||
bool SetSettingTxt( const QByteArray ba );
|
||||
|
||||
//reads a file from the nand and returns it as a qbytearray
|
||||
const QByteArray GetFile( const QString &path );
|
||||
|
||||
//tries to write the given bytearray to a file of the given path
|
||||
bool SaveData( const QByteArray ba, const QString& path );
|
||||
|
||||
//expects a file, not directory
|
||||
void DeleteData( const QString & path );
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef NUSDOWNLOADER_H
|
||||
#define NUSDOWNLOADER_H
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "includes.h"
|
||||
#include "tiktmd.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "savebanner.h"
|
||||
#include "tools.h"
|
||||
|
||||
int TPL_ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height);
|
||||
static int ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height);
|
||||
|
||||
SaveBanner::SaveBanner()
|
||||
{
|
||||
@ -201,7 +201,7 @@ QImage SaveBanner::ConvertTextureToImage( const QByteArray &ba, quint32 w, quint
|
||||
{
|
||||
//qDebug() << "SaveBanner::ConvertTextureToImage" << ba.size() << hex << w << h;
|
||||
quint8* bitmapdata = NULL;//this will hold the converted image
|
||||
int ret = TPL_ConvertRGB5A3ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
|
||||
int ret = ConvertRGB5A3ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
|
||||
if( !ret )
|
||||
{
|
||||
qWarning() << "SaveBanner::ConvertTextureToImage -> error converting image";
|
||||
@ -211,10 +211,9 @@ QImage SaveBanner::ConvertTextureToImage( const QByteArray &ba, quint32 w, quint
|
||||
QImage im2 = im.copy( im.rect() );//make a copy of the image so the "free" wont delete any data we still want
|
||||
free( bitmapdata );
|
||||
return im2;
|
||||
|
||||
}
|
||||
|
||||
int TPL_ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
|
||||
static int ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
|
||||
{
|
||||
quint32 x, y;
|
||||
quint32 x1, y1;
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
//this class creates a dialog used to create & edit a setting.txt for a wii nand filesystem
|
||||
// in most cases, the static function Edit() is what you want to use
|
||||
namespace Ui {
|
||||
class SettingTxtDialog;
|
||||
}
|
||||
@ -15,6 +17,10 @@ public:
|
||||
explicit SettingTxtDialog( QWidget *parent = 0, const QByteArray &old = QByteArray() );
|
||||
~SettingTxtDialog();
|
||||
|
||||
//displays a dialog window with teh given parent. if any data is ginev as old, it will try to populate the dialog with that
|
||||
// otherwise it will use the defaulte values
|
||||
// returns empty if the user clicked cancel, or a bytearray containing an encrypted setting.txt if they clicked ok
|
||||
// the data is ready for writing to a wii nand
|
||||
static QByteArray Edit( QWidget *parent = 0, const QByteArray &old = QByteArray() );
|
||||
static QByteArray LolCrypt( QByteArray ba );
|
||||
|
@ -118,5 +118,5 @@ void SharedContentMap::AddEntry( const QString &app, const QByteArray &hash )
|
||||
{
|
||||
data += app.toAscii() + hash;
|
||||
//qDebug() << "SharedContentMap::AddEntry -> added entry, rechecking this beast";
|
||||
Check();
|
||||
//Check();
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
//class for handling a content.map from a wii nand
|
||||
class SharedContentMap
|
||||
{
|
||||
public:
|
||||
@ -13,11 +14,18 @@ public:
|
||||
//if a path is given, it will check that the hashes in the map match up with the contents in the folder
|
||||
bool Check( const QString &path = QString() );
|
||||
|
||||
//gets a string containing the 8 letter app that matches the given hash.
|
||||
//returns an empty string if the hash is not found in the map
|
||||
QString GetAppFromHash( QByteArray hash );
|
||||
|
||||
//gets the first available u32 that is not already in the map and returns it as a string
|
||||
QString GetNextEmptyCid();
|
||||
|
||||
//adds an entry to the end of the map
|
||||
//! this function doesnt check if the entry already exists
|
||||
void AddEntry( const QString &app, const QByteArray &hash );
|
||||
|
||||
//get the entire data ready for writing to a wii nand
|
||||
const QByteArray Data(){ return data; }
|
||||
|
||||
private:
|
@ -135,9 +135,6 @@ typedef struct _cert_ecdsa {
|
||||
|
||||
#define COMMON_KEY {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}
|
||||
|
||||
#define TITLE_IDH(x) ((u32)(((u64)(x))>>32))
|
||||
#define TITLE_IDL(x) ((u32)(((u64)(x))))
|
||||
|
||||
//just a quick class to try to keep the rest of the code from getting full of the same shit over and over
|
||||
class Ticket
|
||||
{
|
||||
@ -199,18 +196,19 @@ public:
|
||||
quint16 Version();
|
||||
|
||||
//functions to edit the TMD
|
||||
//you probably want to call FakeSign() after using these
|
||||
bool SetTid( quint64 tid );
|
||||
bool SetVersion( quint16 v );
|
||||
bool SetType( quint16 cid, quint16 type );
|
||||
bool SetSize( quint16 cid, quint32 size );
|
||||
bool SetHash( quint16 cid, const QByteArray hash );
|
||||
bool SetType( quint16 i, quint16 type );
|
||||
bool SetSize( quint16 i, quint32 size );
|
||||
bool SetHash( quint16 i, const QByteArray hash );
|
||||
|
||||
bool FakeSign();
|
||||
|
||||
//get the tmd data
|
||||
//returns a qbytearray containing the tmd, from the rsa signature through the last content
|
||||
const QByteArray Data(){ return data; }
|
||||
|
||||
//print the tmd info to qDebug()
|
||||
//print some tmd info to qDebug()
|
||||
void Dbg();
|
||||
|
||||
|
||||
@ -225,7 +223,7 @@ private:
|
||||
void SetPointer();
|
||||
|
||||
//this is just a pointer to the actual good stuff in "data".
|
||||
//whenever data is changes, this pointer will become invalid and needs to be reset
|
||||
//whenever data is changed, this pointer will become invalid and needs to be reset
|
||||
tmd *p_tmd;
|
||||
};
|
||||
|
@ -3,9 +3,9 @@
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
|
||||
QString currentDir;
|
||||
QString cachePath = "./NUS_cache";
|
||||
QString nandPath = "./dump";
|
||||
//QString currentDir;
|
||||
//QString cachePath = "./NUS_cache";
|
||||
//QString nandPath = "./dump";
|
||||
|
||||
char ascii( char s ) {
|
||||
if ( s < 0x20 ) return '.';
|
@ -1,12 +1,14 @@
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
#include "includes.h"
|
||||
//#include "
|
||||
|
||||
#define RU(x,n) (-(-(x) & -(n))) //round up
|
||||
|
||||
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
|
||||
#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) )
|
||||
|
||||
char ascii( char s );
|
||||
void hexdump( const void *d, int len );
|
||||
void hexdump( const QByteArray &d, int from = 0, int len = -1 );
|
||||
|
||||
@ -30,13 +32,13 @@ QByteArray ReadFile( const QString &path );
|
||||
bool WriteFile( const QString &path, const QByteArray ba );
|
||||
|
||||
//keep track of the last folder browsed to when looking for files
|
||||
extern QString currentDir;
|
||||
//extern QString currentDir;
|
||||
|
||||
//folder used to cache stuff downloaded from NUS so duplicate titles dont need to be downloaded
|
||||
extern QString cachePath;
|
||||
//extern QString cachePath;
|
||||
|
||||
//folder to use as the base path for the nand
|
||||
extern QString nandPath;
|
||||
//extern QString nandPath;
|
||||
|
||||
#define CERTS_DAT_SIZE 2560
|
||||
extern const quint8 certs_dat[ CERTS_DAT_SIZE ];
|
1415
WiiQt/u8.cpp
Normal file
1415
WiiQt/u8.cpp
Normal file
File diff suppressed because it is too large
Load Diff
184
WiiQt/u8.h
Normal file
184
WiiQt/u8.h
Normal file
@ -0,0 +1,184 @@
|
||||
#ifndef U8_H
|
||||
#define U8_H
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/*order of the names in the imet header
|
||||
japanese
|
||||
english
|
||||
german
|
||||
french
|
||||
spanish
|
||||
italian
|
||||
dutch
|
||||
simp_chinese
|
||||
trad_chinese
|
||||
korean
|
||||
*/
|
||||
|
||||
struct FEntry
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int Type :8;
|
||||
unsigned int NameOffset :24;
|
||||
};
|
||||
unsigned int TypeName;
|
||||
};
|
||||
union
|
||||
{
|
||||
struct // File Entry
|
||||
{
|
||||
unsigned int FileOffset;
|
||||
unsigned int FileLength;
|
||||
};
|
||||
struct // Dir Entry
|
||||
{
|
||||
unsigned int ParentOffset;
|
||||
unsigned int NextOffset;
|
||||
};
|
||||
unsigned int entry[ 2 ];
|
||||
};
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
U8_Hdr_none = 0,
|
||||
U8_Hdr_IMET_app,//basically the same except the app has 0x40 bytes of padding more than the bnr
|
||||
U8_Hdr_IMET_bnr,
|
||||
U8_Hdr_IMD5
|
||||
};
|
||||
|
||||
//class to handle U8 archives found in wii games & system files
|
||||
// handles different header types, lz77 & ash
|
||||
//! basic usage is to read an existing U8 archive into a qbytearray and pass it to this class through the second constructor or Load()
|
||||
//! you can also create a brand-spankin-new U8 archive by using the first constructor
|
||||
//! check IsOk() to see if that it was loaded ok
|
||||
//! then call Entries() to get a list of everything that is in the archive
|
||||
//! access the data in that archive with AddEntry(), RemoveEntry(), ReplaceEntry(), RenameEntry(), and GetData()
|
||||
class U8
|
||||
{
|
||||
public:
|
||||
//creates a U8 object
|
||||
//if initialize is true, it will call CreateEmptyData() in this U8
|
||||
//you can also set the header type & imet names, though they dont affect the actual data in the archive
|
||||
U8( bool initialize = false, int type = U8_Hdr_none, const QStringList &names = QStringList() );
|
||||
U8( const QByteArray &ba );
|
||||
|
||||
//check if the u8 constructor finished successfully
|
||||
bool IsOK();
|
||||
|
||||
void Load( const QByteArray &ba );
|
||||
|
||||
//set the variables and create an fst with only a root node
|
||||
bool CreateEmptyData();
|
||||
|
||||
//adds an entry to this U8 with the given path, and type, and if it is a file entry, the given data
|
||||
//returns the index of the created entry or -1 on error
|
||||
int AddEntry( const QString &path, int type, const QByteArray &ba = QByteArray() );
|
||||
|
||||
//removes an entry, and all its children, from the archive
|
||||
bool RemoveEntry( const QString &path );
|
||||
|
||||
//replace a file in the archive with different data ( only supports files, no directories )
|
||||
//if autoCompress is true, it will check if the data to be replaced is ASH/LZ77 compressed and make sure the new data is LZ77'd
|
||||
bool ReplaceEntry( const QString &path, const QByteArray &ba = QByteArray(), bool autoCompress = true );
|
||||
|
||||
//remane an entry. this expects a full path of the entry to be named, and newName is only the replacement name ( not the full path )
|
||||
bool RenameEntry( const QString &path, const QString &newName );
|
||||
|
||||
|
||||
//returns the index of an item in the archive FST, or -1 the item is not present
|
||||
//it accepts names like "/arc/anim/". parent is the directory to start looking in
|
||||
int FindEntry( const QString &str, int parent = 0 );
|
||||
quint32 NextEntryInFolder( quint32 current, quint32 directory );
|
||||
QString FstName( const FEntry *entry );
|
||||
QString FstName( quint32 i );
|
||||
|
||||
//gets the data for a path inside the archive
|
||||
//if no path is given, returns the data for the whole archive, starting at the U8 tag
|
||||
//if onlyPayload is true, it will return the data unLZ77'd ( and without its IMET/IMD5 header for nested U8 archives )
|
||||
const QByteArray GetData( const QString &str = QString(), bool onlyPayload = false );
|
||||
|
||||
//get the size of an entry in the archive
|
||||
//if no path is given, returns the size for the whole archive, starting at the U8 tag
|
||||
quint32 GetSize( const QString &str = QString() );
|
||||
|
||||
//returns a list of all the entries in the u8 archive
|
||||
//directories end with "/"
|
||||
const QStringList Entries();
|
||||
|
||||
//check the first 5000 bytes of a file for the u8 tag.
|
||||
//if necessary, un-LZ77 the data before checking
|
||||
//this doesnt check anything else in the archive
|
||||
static bool IsU8( const QByteArray &ba );
|
||||
|
||||
//returns the location of the U8 tag in the first 5000 bytes of the given data
|
||||
static int GetU8Offset( const QByteArray &ba );
|
||||
|
||||
//adds the IMD5 header to the given bytearray and returns it ( original data is modified )
|
||||
static QByteArray AddIMD5( QByteArray ba );
|
||||
|
||||
//returns the U8 archive data with an IMD5 header added
|
||||
//the actual data is not changed
|
||||
const QByteArray AddIMD5();
|
||||
|
||||
//adds the IMET header to the given bytearray and returns it ( original data is modified )
|
||||
static QByteArray AddIMET( QByteArray ba, const QStringList &names );
|
||||
|
||||
//get an IMET header using the given names and sizes
|
||||
//padding type will add 0, 0x40, or 0x80 bytes of 0s to the beginning
|
||||
static QByteArray GetIMET( const QStringList &names, int paddingType = U8_Hdr_IMET_app, quint32 iconSize = 0, quint32 bannerSize = 0, quint32 soundSize = 0 );
|
||||
|
||||
//returns the U8 archive data with an IMET header added
|
||||
//the actual archive data is not changed
|
||||
const QByteArray AddIMET( int paddingType = U8_Hdr_IMET_app );
|
||||
|
||||
//ruterns a list of the names as read from the imet header
|
||||
const QStringList IMETNames();
|
||||
|
||||
//set the imet names
|
||||
//the data in the archive is not changed, but calling AddIMET() on this banner will use the new names
|
||||
void SetImetNames( const QStringList &names );
|
||||
|
||||
//void SetHeaderType( int type );
|
||||
int GetHeaderType();
|
||||
|
||||
|
||||
|
||||
//reads from the fst and makes the list of paths
|
||||
void CreateEntryList();
|
||||
|
||||
|
||||
private:
|
||||
QByteArray data;//data starting at the U8 tag
|
||||
QStringList paths;
|
||||
bool ok;
|
||||
|
||||
//if this archive as a whole is lz77 compressed
|
||||
bool isLz77;
|
||||
|
||||
QStringList imetNames;
|
||||
int headerType;
|
||||
void ReadHeader( const QByteArray &ba );
|
||||
|
||||
|
||||
|
||||
//just a pointer to the fst data.
|
||||
//this pointer needs to be updated any time data is changed
|
||||
FEntry* fst;
|
||||
|
||||
//stored in host endian !
|
||||
quint32 fstSize;
|
||||
quint32 rootnode_offset;
|
||||
quint32 data_offset;
|
||||
quint32 NameOff;
|
||||
|
||||
//a list of the nested u8 archives
|
||||
QMap<QString, U8>nestedU8s;
|
||||
};
|
||||
|
||||
|
||||
#endif // U8_H
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
//class for handling the uid.sys in a virtual nand
|
||||
//
|
||||
class UIDmap
|
||||
{
|
||||
public:
|
||||
@ -18,9 +20,11 @@ public:
|
||||
quint32 GetUid( quint64 tid, bool autoCreate = true );
|
||||
|
||||
//creates a new uid.sys with the system menu entry.
|
||||
//if addFactorySetupDiscs is true, it will add some entries for the setup discs used in the wii factory ( serve no purpose other than to just exist )
|
||||
//if addFactorySetupDiscs is true, it will add some entries for the setup discs used in the wii factory
|
||||
// ( serve no purpose other than to just exist )
|
||||
void CreateNew( bool addFactorySetupDiscs = false );
|
||||
|
||||
//get th entire uid.sys data back in a state ready for writing to a nand
|
||||
const QByteArray Data(){ return data; }
|
||||
|
||||
private:
|
@ -472,14 +472,39 @@ QByteArray Wad::FromDirectory( QDir dir )
|
||||
QList<QByteArray> datas = QList<QByteArray>()<< tmdP << tikP;
|
||||
|
||||
quint16 cnt = t.Count();
|
||||
|
||||
bool tmdChanged = false;
|
||||
for( quint16 i = 0; i < cnt; i++ )
|
||||
{
|
||||
QByteArray appD = ReadFile( dir.absoluteFilePath( t.Cid( i ) + ".app" ) );
|
||||
if( appD.isEmpty() )
|
||||
return QByteArray();
|
||||
|
||||
if( (quint32)appD.size() != t.Size( i ) )
|
||||
{
|
||||
t.SetSize( i, appD.size() );
|
||||
tmdChanged = true;
|
||||
}
|
||||
QByteArray realHash = GetSha1( appD );
|
||||
if( t.Hash( i ) != realHash )
|
||||
{
|
||||
t.SetHash( i, realHash );
|
||||
tmdChanged = true;
|
||||
}
|
||||
datas << appD;
|
||||
}
|
||||
//if something in the tmd changed, fakesign it and replace the data in our list with the new data
|
||||
if( tmdChanged )
|
||||
{
|
||||
if( !t.FakeSign() )
|
||||
{
|
||||
qWarning() << "Error signing the wad";
|
||||
}
|
||||
else
|
||||
{
|
||||
datas.replace( 0, t.Data() );
|
||||
}
|
||||
}
|
||||
Wad wad( datas, false );
|
||||
if( !wad.IsOk() )
|
||||
return QByteArray();
|
@ -5,12 +5,15 @@ TARGET = nandExtract
|
||||
TEMPLATE = app
|
||||
SOURCES += main.cpp \
|
||||
nandwindow.cpp \
|
||||
nandbin.cpp \
|
||||
tools.cpp \
|
||||
aes.c
|
||||
../WiiQt/nandbin.cpp \
|
||||
../WiiQt/tools.cpp \
|
||||
../WiiQt/savebanner.cpp \
|
||||
../WiiQt/aes.c \
|
||||
../WiiQt/sha1.c
|
||||
|
||||
HEADERS += nandwindow.h \
|
||||
nandbin.h \
|
||||
includes.h \
|
||||
tools.h \
|
||||
aes.h
|
||||
../WiiQt/nandbin.h \
|
||||
../WiiQt/tools.h \
|
||||
../WiiQt/tools.h
|
||||
|
||||
FORMS += nandwindow.ui
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "nandwindow.h"
|
||||
#include "ui_nandwindow.h"
|
||||
#include "tools.h"
|
||||
|
||||
NandWindow::NandWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
@ -13,9 +12,9 @@ NandWindow::NandWindow(QWidget *parent) :
|
||||
ui->treeWidget->header()->resizeSection( 0, fm.width( QString( 22, 'W' ) ) );//name
|
||||
ui->treeWidget->header()->resizeSection( 1, fm.width( "WWWWW" ) );//entry #
|
||||
ui->treeWidget->header()->resizeSection( 2, fm.width( "WWWWW" ) );//size
|
||||
ui->treeWidget->header()->resizeSection( 3, fm.width( "WWWWWWWWWW" ) );//uid
|
||||
ui->treeWidget->header()->resizeSection( 4, fm.width( "WWWWWWWWWW" ) );//gid
|
||||
ui->treeWidget->header()->resizeSection( 5, fm.width( "WWWWWWWWWW" ) );//x3
|
||||
ui->treeWidget->header()->resizeSection( 3, fm.width( "WWWWWWWWW" ) );//uid
|
||||
ui->treeWidget->header()->resizeSection( 4, fm.width( "WWWWWWWWW" ) );//gid
|
||||
ui->treeWidget->header()->resizeSection( 5, fm.width( "WWWWWWWWW" ) );//x3
|
||||
ui->treeWidget->header()->resizeSection( 6, fm.width( "WWWWW" ) );//mode
|
||||
ui->treeWidget->header()->resizeSection( 7, fm.width( "WWWWW" ) );//attr
|
||||
|
||||
@ -131,4 +130,6 @@ void NandWindow::on_actionOpen_Nand_triggered()
|
||||
//delete the made up root item
|
||||
delete tree;
|
||||
ui->statusBar->showMessage( "Loaded " + path, 5000 );
|
||||
|
||||
//nandBin.GetData( "/title/00000001/00000002/data/setting.txt" );//testing 1,2,1,2
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define NANDWINDOW_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "nandbin.h"
|
||||
#include "../WiiQt/nandbin.h"
|
||||
|
||||
namespace Ui {
|
||||
class NandWindow;
|
||||
|
400
nand_dump/aes.c
400
nand_dump/aes.c
@ -1,400 +0,0 @@
|
||||
/* Rijndael Block Cipher - aes.c
|
||||
|
||||
Written by Mike Scott 21st April 1999
|
||||
mike@compapp.dcu.ie
|
||||
|
||||
Permission for free direct or derivative use is granted subject
|
||||
to compliance with any conditions that the originators of the
|
||||
algorithm place on its exploitation.
|
||||
|
||||
*/
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>*/
|
||||
|
||||
#define u8 unsigned char /* 8 bits */
|
||||
#define u32 unsigned long /* 32 bits */
|
||||
#define u64 unsigned long long
|
||||
|
||||
/* rotates x one bit to the left */
|
||||
|
||||
#define ROTL(x) (((x)>>7)|((x)<<1))
|
||||
|
||||
/* Rotates 32-bit word left by 1, 2 or 3 byte */
|
||||
|
||||
#define ROTL8(x) (((x)<<8)|((x)>>24))
|
||||
#define ROTL16(x) (((x)<<16)|((x)>>16))
|
||||
#define ROTL24(x) (((x)<<24)|((x)>>8))
|
||||
|
||||
/* Fixed Data */
|
||||
|
||||
static u8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
|
||||
|
||||
static u8 fbsub[256];
|
||||
static u8 rbsub[256];
|
||||
static u8 ptab[256],ltab[256];
|
||||
static u32 ftable[256];
|
||||
static u32 rtable[256];
|
||||
static u32 rco[30];
|
||||
|
||||
/* Parameter-dependent data */
|
||||
|
||||
int Nk,Nb,Nr;
|
||||
u8 fi[24],ri[24];
|
||||
u32 fkey[120];
|
||||
u32 rkey[120];
|
||||
|
||||
static u32 pack(u8 *b)
|
||||
{ /* pack bytes into a 32-bit Word */
|
||||
return ((u32)b[3]<<24)|((u32)b[2]<<16)|((u32)b[1]<<8)|(u32)b[0];
|
||||
}
|
||||
|
||||
static void unpack(u32 a,u8 *b)
|
||||
{ /* unpack bytes from a word */
|
||||
b[0]=(u8)a;
|
||||
b[1]=(u8)(a>>8);
|
||||
b[2]=(u8)(a>>16);
|
||||
b[3]=(u8)(a>>24);
|
||||
}
|
||||
|
||||
static u8 xtime(u8 a)
|
||||
{
|
||||
u8 b;
|
||||
if (a&0x80) b=0x1B;
|
||||
else b=0;
|
||||
a<<=1;
|
||||
a^=b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static u8 bmul(u8 x,u8 y)
|
||||
{ /* x.y= AntiLog(Log(x) + Log(y)) */
|
||||
if (x && y) return ptab[(ltab[x]+ltab[y])%255];
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static u32 SubByte(u32 a)
|
||||
{
|
||||
u8 b[4];
|
||||
unpack(a,b);
|
||||
b[0]=fbsub[b[0]];
|
||||
b[1]=fbsub[b[1]];
|
||||
b[2]=fbsub[b[2]];
|
||||
b[3]=fbsub[b[3]];
|
||||
return pack(b);
|
||||
}
|
||||
|
||||
static u8 product(u32 x,u32 y)
|
||||
{ /* dot product of two 4-byte arrays */
|
||||
u8 xb[4],yb[4];
|
||||
unpack(x,xb);
|
||||
unpack(y,yb);
|
||||
return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]);
|
||||
}
|
||||
|
||||
static u32 InvMixCol(u32 x)
|
||||
{ /* matrix Multiplication */
|
||||
u32 y,m;
|
||||
u8 b[4];
|
||||
|
||||
m=pack(InCo);
|
||||
b[3]=product(m,x);
|
||||
m=ROTL24(m);
|
||||
b[2]=product(m,x);
|
||||
m=ROTL24(m);
|
||||
b[1]=product(m,x);
|
||||
m=ROTL24(m);
|
||||
b[0]=product(m,x);
|
||||
y=pack(b);
|
||||
return y;
|
||||
}
|
||||
|
||||
u8 ByteSub(u8 x)
|
||||
{
|
||||
u8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
|
||||
x=y; x=ROTL(x);
|
||||
y^=x; x=ROTL(x);
|
||||
y^=x; x=ROTL(x);
|
||||
y^=x; x=ROTL(x);
|
||||
y^=x; y^=0x63;
|
||||
return y;
|
||||
}
|
||||
|
||||
void gentables(void)
|
||||
{ /* generate tables */
|
||||
int i;
|
||||
u8 y,b[4];
|
||||
|
||||
/* use 3 as primitive root to generate power and log tables */
|
||||
|
||||
ltab[0]=0;
|
||||
ptab[0]=1; ltab[1]=0;
|
||||
ptab[1]=3; ltab[3]=1;
|
||||
for (i=2;i<256;i++)
|
||||
{
|
||||
ptab[i]=ptab[i-1]^xtime(ptab[i-1]);
|
||||
ltab[ptab[i]]=i;
|
||||
}
|
||||
|
||||
/* affine transformation:- each bit is xored with itself shifted one bit */
|
||||
|
||||
fbsub[0]=0x63;
|
||||
rbsub[0x63]=0;
|
||||
for (i=1;i<256;i++)
|
||||
{
|
||||
y=ByteSub((u8)i);
|
||||
fbsub[i]=y; rbsub[y]=i;
|
||||
}
|
||||
|
||||
for (i=0,y=1;i<30;i++)
|
||||
{
|
||||
rco[i]=y;
|
||||
y=xtime(y);
|
||||
}
|
||||
|
||||
/* calculate forward and reverse tables */
|
||||
for (i=0;i<256;i++)
|
||||
{
|
||||
y=fbsub[i];
|
||||
b[3]=y^xtime(y); b[2]=y;
|
||||
b[1]=y; b[0]=xtime(y);
|
||||
ftable[i]=pack(b);
|
||||
|
||||
y=rbsub[i];
|
||||
b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y);
|
||||
b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y);
|
||||
rtable[i]=pack(b);
|
||||
}
|
||||
}
|
||||
|
||||
void gkey(int nb,int nk,u8 *key)
|
||||
{ /* blocksize=32*nb bits. Key=32*nk bits */
|
||||
/* currently nb,bk = 4, 6 or 8 */
|
||||
/* key comes as 4*Nk bytes */
|
||||
/* Key Scheduler. Create expanded encryption key */
|
||||
int i,j,k,m,N;
|
||||
int C1,C2,C3;
|
||||
u32 CipherKey[8];
|
||||
|
||||
Nb=nb; Nk=nk;
|
||||
|
||||
/* Nr is number of rounds */
|
||||
if (Nb>=Nk) Nr=6+Nb;
|
||||
else Nr=6+Nk;
|
||||
|
||||
C1=1;
|
||||
if (Nb<8) { C2=2; C3=3; }
|
||||
else { C2=3; C3=4; }
|
||||
|
||||
/* pre-calculate forward and reverse increments */
|
||||
for (m=j=0;j<nb;j++,m+=3)
|
||||
{
|
||||
fi[m]=(j+C1)%nb;
|
||||
fi[m+1]=(j+C2)%nb;
|
||||
fi[m+2]=(j+C3)%nb;
|
||||
ri[m]=(nb+j-C1)%nb;
|
||||
ri[m+1]=(nb+j-C2)%nb;
|
||||
ri[m+2]=(nb+j-C3)%nb;
|
||||
}
|
||||
|
||||
N=Nb*(Nr+1);
|
||||
|
||||
for (i=j=0;i<Nk;i++,j+=4)
|
||||
{
|
||||
CipherKey[i]=pack(key+j);
|
||||
}
|
||||
for (i=0;i<Nk;i++) fkey[i]=CipherKey[i];
|
||||
for (j=Nk,k=0;j<N;j+=Nk,k++)
|
||||
{
|
||||
fkey[j]=fkey[j-Nk]^SubByte(ROTL24(fkey[j-1]))^rco[k];
|
||||
if (Nk<=6)
|
||||
{
|
||||
for (i=1;i<Nk && (i+j)<N;i++)
|
||||
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=1;i<4 &&(i+j)<N;i++)
|
||||
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
|
||||
if ((j+4)<N) fkey[j+4]=fkey[j+4-Nk]^SubByte(fkey[j+3]);
|
||||
for (i=5;i<Nk && (i+j)<N;i++)
|
||||
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* now for the expanded decrypt key in reverse order */
|
||||
|
||||
for (j=0;j<Nb;j++) rkey[j+N-Nb]=fkey[j];
|
||||
for (i=Nb;i<N-Nb;i+=Nb)
|
||||
{
|
||||
k=N-Nb-i;
|
||||
for (j=0;j<Nb;j++) rkey[k+j]=InvMixCol(fkey[i+j]);
|
||||
}
|
||||
for (j=N-Nb;j<N;j++) rkey[j-N+Nb]=fkey[j];
|
||||
}
|
||||
|
||||
|
||||
/* There is an obvious time/space trade-off possible here. *
|
||||
* Instead of just one ftable[], I could have 4, the other *
|
||||
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
|
||||
|
||||
void encrypt(u8 *buff)
|
||||
{
|
||||
int i,j,k,m;
|
||||
u32 a[8],b[8],*x,*y,*t;
|
||||
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
a[i]=pack(buff+j);
|
||||
a[i]^=fkey[i];
|
||||
}
|
||||
k=Nb;
|
||||
x=a; y=b;
|
||||
|
||||
/* State alternates between a and b */
|
||||
for (i=1;i<Nr;i++)
|
||||
{ /* Nr is number of rounds. May be odd. */
|
||||
|
||||
/* if Nb is fixed - unroll this next
|
||||
loop and hard-code in the values of fi[] */
|
||||
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{ /* deal with each 32-bit element of the State */
|
||||
/* This is the time-critical bit */
|
||||
y[j]=fkey[k++]^ftable[(u8)x[j]]^
|
||||
ROTL8(ftable[(u8)(x[fi[m]]>>8)])^
|
||||
ROTL16(ftable[(u8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24(ftable[(u8)(x[fi[m+2]]>>24)]);
|
||||
}
|
||||
t=x; x=y; y=t; /* swap pointers */
|
||||
}
|
||||
|
||||
/* Last Round - unroll if possible */
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{
|
||||
y[j]=fkey[k++]^(u32)fbsub[(u8)x[j]]^
|
||||
ROTL8((u32)fbsub[(u8)(x[fi[m]]>>8)])^
|
||||
ROTL16((u32)fbsub[(u8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24((u32)fbsub[(u8)(x[fi[m+2]]>>24)]);
|
||||
}
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
unpack(y[i],(u8 *)&buff[j]);
|
||||
x[i]=y[i]=0; /* clean up stack */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void decrypt(u8 *buff)
|
||||
{
|
||||
int i,j,k,m;
|
||||
u32 a[8],b[8],*x,*y,*t;
|
||||
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
a[i]=pack(buff+j);
|
||||
a[i]^=rkey[i];
|
||||
}
|
||||
k=Nb;
|
||||
x=a; y=b;
|
||||
|
||||
/* State alternates between a and b */
|
||||
for (i=1;i<Nr;i++)
|
||||
{ /* Nr is number of rounds. May be odd. */
|
||||
|
||||
/* if Nb is fixed - unroll this next
|
||||
loop and hard-code in the values of ri[] */
|
||||
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{ /* This is the time-critical bit */
|
||||
y[j]=rkey[k++]^rtable[(u8)x[j]]^
|
||||
ROTL8(rtable[(u8)(x[ri[m]]>>8)])^
|
||||
ROTL16(rtable[(u8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24(rtable[(u8)(x[ri[m+2]]>>24)]);
|
||||
}
|
||||
t=x; x=y; y=t; /* swap pointers */
|
||||
}
|
||||
|
||||
/* Last Round - unroll if possible */
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{
|
||||
y[j]=rkey[k++]^(u32)rbsub[(u8)x[j]]^
|
||||
ROTL8((u32)rbsub[(u8)(x[ri[m]]>>8)])^
|
||||
ROTL16((u32)rbsub[(u8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24((u32)rbsub[(u8)(x[ri[m+2]]>>24)]);
|
||||
}
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
unpack(y[i],(u8 *)&buff[j]);
|
||||
x[i]=y[i]=0; /* clean up stack */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void aes_set_key(u8 *key) {
|
||||
gentables();
|
||||
gkey(4, 4, key);
|
||||
}
|
||||
|
||||
// CBC mode decryption
|
||||
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
||||
u8 block[16];
|
||||
unsigned int blockno = 0, i;
|
||||
|
||||
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
||||
|
||||
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
|
||||
unsigned int fraction;
|
||||
if (blockno == (len / sizeof(block))) { // last block
|
||||
fraction = len % sizeof(block);
|
||||
if (fraction == 0) break;
|
||||
memset(block, 0, sizeof(block));
|
||||
} else fraction = 16;
|
||||
|
||||
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
|
||||
memcpy(block, inbuf + blockno * sizeof(block), fraction);
|
||||
decrypt(block);
|
||||
u8 *ctext_ptr;
|
||||
if (blockno == 0) ctext_ptr = iv;
|
||||
else ctext_ptr = inbuf + (blockno-1) * sizeof(block);
|
||||
|
||||
for(i=0; i < fraction; i++)
|
||||
outbuf[blockno * sizeof(block) + i] =
|
||||
ctext_ptr[i] ^ block[i];
|
||||
// debug_printf("Block %d output: ", blockno);
|
||||
// hexdump(outbuf + blockno*sizeof(block), 16);
|
||||
}
|
||||
}
|
||||
|
||||
// CBC mode encryption
|
||||
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
||||
u8 block[16];
|
||||
unsigned int blockno = 0, i;
|
||||
|
||||
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
||||
|
||||
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
|
||||
unsigned int fraction;
|
||||
if (blockno == (len / sizeof(block))) { // last block
|
||||
fraction = len % sizeof(block);
|
||||
if (fraction == 0) break;
|
||||
memset(block, 0, sizeof(block));
|
||||
} else fraction = 16;
|
||||
|
||||
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
|
||||
memcpy(block, inbuf + blockno * sizeof(block), fraction);
|
||||
|
||||
for(i=0; i < fraction; i++)
|
||||
block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i];
|
||||
|
||||
encrypt(block);
|
||||
memcpy(iv, block, sizeof(block));
|
||||
memcpy(outbuf + blockno * sizeof(block), block, sizeof(block));
|
||||
// debug_printf("Block %d output: ", blockno);
|
||||
// hexdump(outbuf + blockno*sizeof(block), 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
#ifndef __AES_H_
|
||||
#define __AES_H_
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void aes_encrypt( quint8 *iv, const quint8 *inbuf, quint8 *outbuf, unsigned long long len );
|
||||
void aes_decrypt( quint8 *iv, const quint8 *inbuf, quint8 *outbuf, unsigned long long len );
|
||||
void aes_set_key( const quint8 *key );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__AES_H_
|
||||
|
@ -1,12 +1,10 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "settingtxtdialog.h"
|
||||
#include "uidmap.h"
|
||||
#include "sha1.h"
|
||||
#include "tiktmd.h"
|
||||
#include "tools.h"
|
||||
#include "aes.h"
|
||||
#include "wad.h"
|
||||
#include "../WiiQt/settingtxtdialog.h"
|
||||
#include "../WiiQt/tiktmd.h"
|
||||
#include "../WiiQt/tools.h"
|
||||
#include "../WiiQt/wad.h"
|
||||
|
||||
|
||||
MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::MainWindow ), nus ( this )
|
||||
{
|
||||
@ -23,6 +21,11 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M
|
||||
connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) );
|
||||
|
||||
//TODO, really get these paths from settings
|
||||
|
||||
QString cachePath = "./NUS_cache";
|
||||
QString nandPath = "./dump";
|
||||
|
||||
|
||||
ui->lineEdit_cachePath->setText( cachePath );
|
||||
ui->lineEdit_nandPath->setText( nandPath );
|
||||
ui->lineEdit_extractPath->setText( "./downloaded" );
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "nusdownloader.h"
|
||||
#include "nanddump.h"
|
||||
#include "../WiiQt/includes.h"
|
||||
#include "../WiiQt/nusdownloader.h"
|
||||
#include "../WiiQt/nanddump.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
|
@ -13,29 +13,27 @@ TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp\
|
||||
mainwindow.cpp \
|
||||
tools.cpp \
|
||||
uidmap.cpp \
|
||||
sharedcontentmap.cpp \
|
||||
sha1.c \
|
||||
tiktmd.cpp \
|
||||
aes.c \
|
||||
nusdownloader.cpp \
|
||||
nanddump.cpp \
|
||||
settingtxtdialog.cpp \
|
||||
wad.cpp
|
||||
../WiiQt/tools.cpp \
|
||||
../WiiQt/sharedcontentmap.cpp \
|
||||
../WiiQt/tiktmd.cpp \
|
||||
../WiiQt/nusdownloader.cpp \
|
||||
../WiiQt/uidmap.cpp \
|
||||
../WiiQt/nanddump.cpp \
|
||||
../WiiQt/settingtxtdialog.cpp \
|
||||
../WiiQt/wad.cpp \
|
||||
../WiiQt/aes.c \
|
||||
../WiiQt/sha1.c
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
tools.h \
|
||||
includes.h \
|
||||
uidmap.h \
|
||||
sharedcontentmap.h \
|
||||
sha1.h \
|
||||
tiktmd.h \
|
||||
aes.h \
|
||||
nusdownloader.h \
|
||||
nanddump.h \
|
||||
settingtxtdialog.h \
|
||||
wad.h
|
||||
../WiiQt/tools.h \
|
||||
../WiiQt/uidmap.h \
|
||||
../WiiQt/sharedcontentmap.h \
|
||||
../WiiQt/tiktmd.h \
|
||||
../WiiQt/nusdownloader.h \
|
||||
../WiiQt/uidmap.h \
|
||||
../WiiQt/nanddump.h \
|
||||
../WiiQt/settingtxtdialog.h \
|
||||
../WiiQt/wad.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
settingtxtdialog.ui
|
||||
../WiiQt/settingtxtdialog.ui
|
||||
|
@ -1,6 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "tools.h"
|
||||
#include "savebanner.h"
|
||||
|
||||
//TODO... get these from settings and dont use global variables
|
||||
static QString pcPath = "./saveBackups";
|
||||
static QString sneekPath = "/media/SDHC_4GB";
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), bannerthread( this )
|
||||
{
|
||||
@ -108,6 +113,7 @@ void MainWindow::on_actionSet_Sneek_Path_triggered()
|
||||
if( p.isEmpty() )
|
||||
return;
|
||||
|
||||
ui->listWidget_sneekSaves->clear();
|
||||
GetSavesFromSneek( p );
|
||||
}
|
||||
|
||||
|
@ -12,19 +12,21 @@ TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp\
|
||||
mainwindow.cpp \
|
||||
savebanner.cpp \
|
||||
savelistitem.cpp \
|
||||
saveloadthread.cpp \
|
||||
tools.cpp
|
||||
../WiiQt/tools.cpp \
|
||||
../WiiQt/savebanner.cpp \
|
||||
../WiiQt/aes.c \
|
||||
../WiiQt/sha1.c
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
includes.h \
|
||||
savebanner.h \
|
||||
savelistitem.h \
|
||||
saveloadthread.h \
|
||||
tools.h
|
||||
saveloadthread.h\
|
||||
../WiiQt/tools.h
|
||||
|
||||
FORMS += mainwindow.ui
|
||||
|
||||
RESOURCES += \
|
||||
rc.qrc
|
||||
|
||||
INCPATH += "../WiiQt"
|
||||
|
@ -70,6 +70,14 @@ void SaveLoadThread::run()
|
||||
QFileInfoList fiL2 = subDir.entryInfoList();
|
||||
cnt += fiL2.size();
|
||||
|
||||
subDir.setPath( basePath + "/title/00010002" );
|
||||
QFileInfoList fiL3 = subDir.entryInfoList();
|
||||
cnt += fiL3.size();
|
||||
|
||||
subDir.setPath( basePath + "/title/00010004" );
|
||||
QFileInfoList fiL4 = subDir.entryInfoList();
|
||||
cnt += fiL4.size();
|
||||
|
||||
foreach( QFileInfo f, fiL )
|
||||
{
|
||||
i++;
|
||||
@ -97,9 +105,39 @@ void SaveLoadThread::run()
|
||||
QByteArray stuff = ff.readAll();
|
||||
ff.close();
|
||||
|
||||
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
|
||||
emit SendItem( stuff, QString( "00010001" + f.fileName() ), type, size );
|
||||
}
|
||||
foreach( QFileInfo f, fiL3 )
|
||||
{
|
||||
i++;
|
||||
emit SendProgress( (int)( ( (float)( i ) / (float)cnt ) * (float)100 ) );
|
||||
|
||||
QFile ff( f.absoluteFilePath() + "/data/banner.bin" );
|
||||
if( !ff.exists() || !ff.open( QIODevice::ReadOnly ) )
|
||||
continue;
|
||||
|
||||
QByteArray stuff = ff.readAll();
|
||||
ff.close();
|
||||
|
||||
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
|
||||
emit SendItem( stuff, QString( "00010002" + f.fileName() ), type, size );
|
||||
}
|
||||
foreach( QFileInfo f, fiL4 )
|
||||
{
|
||||
i++;
|
||||
emit SendProgress( (int)( ( (float)( i ) / (float)cnt ) * (float)100 ) );
|
||||
|
||||
QFile ff( f.absoluteFilePath() + "/data/banner.bin" );
|
||||
if( !ff.exists() || !ff.open( QIODevice::ReadOnly ) )
|
||||
continue;
|
||||
|
||||
QByteArray stuff = ff.readAll();
|
||||
ff.close();
|
||||
|
||||
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
|
||||
emit SendItem( stuff, QString( "00010004" + f.fileName() ), type, size );
|
||||
}
|
||||
|
||||
emit SendProgress( 100 );
|
||||
emit SendDone( type );
|
||||
|
@ -1,46 +0,0 @@
|
||||
#include "tools.h"
|
||||
#include "includes.h"
|
||||
|
||||
QString currentDir;
|
||||
QString pcPath = "./saveBackups";
|
||||
QString sneekPath = "/media/SDHC_4GB";
|
||||
|
||||
char ascii( char s ) {
|
||||
if ( s < 0x20 ) return '.';
|
||||
if ( s > 0x7E ) return '.';
|
||||
return s;
|
||||
}
|
||||
void hexdump( const void *d, int len ) {
|
||||
unsigned char *data;
|
||||
int i, off;
|
||||
data = (unsigned char*)d;
|
||||
fprintf( stderr, "\n");
|
||||
for ( off = 0; off < len; off += 16 ) {
|
||||
fprintf( stderr, "%08x ", off );
|
||||
for ( i=0; i<16; i++ )
|
||||
{
|
||||
if( ( i + 1 ) % 4 )
|
||||
{
|
||||
if ( ( i + off ) >= len ) fprintf( stderr," ");
|
||||
else fprintf( stderr,"%02x",data[ off + i ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( i + off ) >= len ) fprintf( stderr," ");
|
||||
else fprintf( stderr,"%02x ",data[ off + i ]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf( stderr, " " );
|
||||
for ( i = 0; i < 16; i++ )
|
||||
if ( ( i + off) >= len ) fprintf( stderr," ");
|
||||
else fprintf( stderr,"%c", ascii( data[ off + i ]));
|
||||
fprintf( stderr,"\n");
|
||||
}
|
||||
fflush( stderr );
|
||||
}
|
||||
|
||||
void hexdump( const QByteArray &d, int from, int len )
|
||||
{
|
||||
hexdump( d.data() + from, len == -1 ? d.size() : len );
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
#include "includes.h"
|
||||
|
||||
#define RU(x,n) (-(-(x) & -(n))) //round up
|
||||
|
||||
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
|
||||
#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) )
|
||||
|
||||
char ascii( char s );
|
||||
void hexdump( const void *d, int len );
|
||||
void hexdump( const QByteArray &d, int from = 0, int len = -1 );
|
||||
|
||||
//keep track of the last folder browsed to when looking for files
|
||||
extern QString currentDir;
|
||||
|
||||
extern QString pcPath;
|
||||
extern QString sneekPath;
|
||||
|
||||
#endif // TOOLS_H
|
Loading…
Reference in New Issue
Block a user