mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-12-26 21:01:51 +01:00
* fix bugs in the nandBin delete
* fiix bug when writing supercluster * add macros for nand attributes * adding another example program for creating nand.bin and adding wads. it SEEMS to work as expected, but still, use it with EXTREME CAUTION * changed default NUS_Cache path in NUS downloader to parent directly so the 2 example programs can share the same cache * added "-all" argument for the nandBinchecker git-svn-id: http://wiiqt.googlecode.com/svn/trunk@26 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
parent
e20fcdaeb4
commit
c41bc634a1
@ -15,7 +15,10 @@ NandBin::NandBin( QObject * parent, const QString &path ) : QObject( parent )
|
|||||||
NandBin::~NandBin()
|
NandBin::~NandBin()
|
||||||
{
|
{
|
||||||
if( f.isOpen() )
|
if( f.isOpen() )
|
||||||
|
{
|
||||||
|
f.flush();
|
||||||
f.close();
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
if( root )
|
if( root )
|
||||||
delete root;
|
delete root;
|
||||||
@ -147,6 +150,7 @@ bool NandBin::CreateNew( const QString &path, QByteArray keys, QByteArray first8
|
|||||||
|
|
||||||
QTreeWidgetItem *NandBin::GetTree()
|
QTreeWidgetItem *NandBin::GetTree()
|
||||||
{
|
{
|
||||||
|
//qDebug() << "NandBin::GetTree()";
|
||||||
return root->clone();
|
return root->clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +375,17 @@ bool NandBin::InitNand( QIcon dirs, QIcon files )
|
|||||||
|
|
||||||
root = new QTreeWidgetItem( QStringList() << nandPath );
|
root = new QTreeWidgetItem( QStringList() << nandPath );
|
||||||
AddChildren( root, 0 );
|
AddChildren( root, 0 );
|
||||||
|
/*#ifdef NAND_BIN_CAN_WRITE
|
||||||
|
CreateEntry( "/testDir", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW );
|
||||||
|
quint16 pp = CreateEntry( "/testDir/testFile", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_RW );
|
||||||
|
qDebug() << "created entry" << pp;
|
||||||
|
Delete( "/testDir/testFile" );
|
||||||
|
pp = CreateEntry( "/testDir/testFile", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_RW );
|
||||||
|
qDebug() << "created entry" << pp;
|
||||||
|
SetData( pp, QByteArray( 0x10000, '\x0' ) );
|
||||||
|
|
||||||
|
WriteMetaData();
|
||||||
|
#endif*/
|
||||||
|
|
||||||
//checkout the blocks for boot1&2
|
//checkout the blocks for boot1&2
|
||||||
QList<QByteArray>blocks;
|
QList<QByteArray>blocks;
|
||||||
@ -390,120 +404,10 @@ bool NandBin::InitNand( QIcon dirs, QIcon files )
|
|||||||
blocks << block;
|
blocks << block;
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug shitzz
|
|
||||||
/*QList<quint16> fffcs;
|
|
||||||
QList<quint16> ffffs;
|
|
||||||
QList<quint16> fffds;
|
|
||||||
for( quint16 i = 0; i < 0x8000; i++ )
|
|
||||||
{
|
|
||||||
switch( fats.at( i ) )
|
|
||||||
{
|
|
||||||
case 0xFFFB:
|
|
||||||
break;
|
|
||||||
case 0xFFFC:
|
|
||||||
fffcs << i;
|
|
||||||
break;
|
|
||||||
case 0xFFFD:
|
|
||||||
fffds << i;
|
|
||||||
break;
|
|
||||||
case 0xFFFE:
|
|
||||||
break;
|
|
||||||
case 0xFFFF:
|
|
||||||
ffffs << i;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
/*foreach( quint16 cl, fffds )
|
|
||||||
{
|
|
||||||
qDebug() << "bad cluster" << hex << cl;
|
|
||||||
for( quint16 i = 0; i < 8; i++ )
|
|
||||||
{
|
|
||||||
QByteArray page = GetPage( (cl * 8 ) + i, true );
|
|
||||||
for( quint16 j = 0; j < page.size(); j++ )
|
|
||||||
{
|
|
||||||
if( page.at( j ) != '\0' )
|
|
||||||
{
|
|
||||||
hexdump( page );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//hexdump( page );
|
|
||||||
}
|
|
||||||
//break;
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*qDebug() << "total ffff clusters:" << ffffs.size();
|
|
||||||
quint16 u = 0;
|
|
||||||
while( ffffs.size() )
|
|
||||||
{
|
|
||||||
quint16 fc = ffffs.takeFirst();
|
|
||||||
if( fc < 0x40 || fc >= 0x7F00 )
|
|
||||||
continue;
|
|
||||||
QByteArray cl = GetCluster( fc, false );
|
|
||||||
while( ffffs.size() && ( ( fc / 8 ) == ( ffffs.at( 0 ) / 8 ) ) )
|
|
||||||
{
|
|
||||||
fc = ffffs.takeFirst();
|
|
||||||
if( fc < 0x40 || fc >= 0x7F00 )
|
|
||||||
continue;
|
|
||||||
cl += GetCluster( fc, false );
|
|
||||||
|
|
||||||
}
|
|
||||||
WriteFile( QString("./aaaa_ff_%1_%2.bin" ).arg( u++).arg( fc ), cl );
|
|
||||||
}*/
|
|
||||||
/*QList<quint16> fcBlocks;
|
|
||||||
quint16 cnt = fffcs.size();
|
|
||||||
quint16 rr = 0;
|
|
||||||
for( quint16 i = 0; i < cnt; i++ )
|
|
||||||
{
|
|
||||||
quint16 block = fffcs.at( i )/8;
|
|
||||||
if( !fcBlocks.contains( block ) )
|
|
||||||
fcBlocks << block;
|
|
||||||
|
|
||||||
if( fffcs.at( i ) < 0x40 || fffcs.at( i ) >= 0x7F00 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rr++;
|
|
||||||
}
|
|
||||||
qDebug() << "fcBlocks:" << fcBlocks << "total reserved clusters:" << fffcs.size() << "reserved not used for superblock/boot" << rr;*/
|
|
||||||
/*quint16 ppp = 0;
|
|
||||||
for( quint16 i = 0; i < fcBlocks.size(); i++ )
|
|
||||||
{
|
|
||||||
for( quint16 j = 0; j < 8; j++ )
|
|
||||||
{
|
|
||||||
if( !fffcs.contains( ( i * 8 ) + j ) )
|
|
||||||
{
|
|
||||||
ppp++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "partial reserved blocks:" << ppp;*/
|
|
||||||
/*quint16 u = 0;
|
|
||||||
while( fffcs.size() )
|
|
||||||
{
|
|
||||||
quint16 fc = fffcs.takeFirst();
|
|
||||||
if( fc < 0x40 || fc >= 0x7F00 )
|
|
||||||
continue;
|
|
||||||
QByteArray cl = GetCluster( fc );
|
|
||||||
while( fffcs.size() && ( ( fc / 8 ) == ( fffcs.at( 0 ) / 8 ) ) )
|
|
||||||
{
|
|
||||||
fc = fffcs.takeFirst();
|
|
||||||
if( fc < 0x40 || fc >= 0x7F00 )
|
|
||||||
continue;
|
|
||||||
cl += GetCluster( fc );
|
|
||||||
|
|
||||||
}
|
|
||||||
WriteFile( QString("./aaaa_fc_%1_%2.bin" ).arg( u++).arg( fc ), cl );
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
if( !bootBlocks.SetBlocks( blocks ) )
|
if( !bootBlocks.SetBlocks( blocks ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ShowInfo();
|
//ShowInfo();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -764,11 +668,7 @@ quint16 NandBin::GetFAT( quint16 fat_entry )
|
|||||||
{
|
{
|
||||||
if( fstInited )
|
if( fstInited )
|
||||||
return fats.at( fat_entry );
|
return fats.at( fat_entry );
|
||||||
/*
|
|
||||||
* compensate for "off-16" storage at beginning of superblock
|
|
||||||
* 53 46 46 53 XX XX XX XX 00 00 00 00
|
|
||||||
* S F F S "version" padding?
|
|
||||||
* 1 2 3 4 5 6*/
|
|
||||||
fat_entry += 6;
|
fat_entry += 6;
|
||||||
|
|
||||||
// location in fat of cluster chain
|
// location in fat of cluster chain
|
||||||
@ -1127,7 +1027,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr
|
|||||||
QByteArray spareData( 0x40, '\0' );
|
QByteArray spareData( 0x40, '\0' );
|
||||||
quint8* sp = (quint8*)spareData.data();
|
quint8* sp = (quint8*)spareData.data();
|
||||||
QByteArray ecc = spare.CalcEcc( data.mid( i * 0x800, 0x800 ) );
|
QByteArray ecc = spare.CalcEcc( data.mid( i * 0x800, 0x800 ) );
|
||||||
memcpy( sp + 0x30, ecc.data(), 0x14 );
|
memcpy( sp + 0x30, ecc.data(), 0x10 );
|
||||||
sp[ 0 ] = 0xff; // good block
|
sp[ 0 ] = 0xff; // good block
|
||||||
if( !hmac.isEmpty() )
|
if( !hmac.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -1138,7 +1038,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr
|
|||||||
}
|
}
|
||||||
else if( i == 7 )
|
else if( i == 7 )
|
||||||
{
|
{
|
||||||
memcpy( (char*)sp + 1, hmac.data() + 12, 8 );
|
memcpy( (char*)sp + 1, (char*)(hmac.data()) + 12, 8 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( !WritePage( pageNo + i, data.mid( i * 0x800, 0x800 ) + spareData ) )
|
if( !WritePage( pageNo + i, data.mid( i * 0x800, 0x800 ) + spareData ) )
|
||||||
@ -1192,10 +1092,11 @@ quint16 NandBin::CreateNode( const QString &name, quint32 uid, quint16 gid, quin
|
|||||||
attr = attr | ( ( user_perm & 3 ) << 6 ) | ( ( group_perm & 3 ) << 4 ) | ( ( other_perm & 3 ) << 2 );
|
attr = attr | ( ( user_perm & 3 ) << 6 ) | ( ( group_perm & 3 ) << 4 ) | ( ( other_perm & 3 ) << 2 );
|
||||||
|
|
||||||
quint32 i;
|
quint32 i;
|
||||||
|
//qDebug() << "looking for first empty node";
|
||||||
for( i = 1; i < 0x17ff; i++ )//cant be entry 0 because that is the root
|
for( i = 1; i < 0x17ff; i++ )//cant be entry 0 because that is the root
|
||||||
{
|
{
|
||||||
fst_t fst = fsts[ i ];
|
//qDebug() << hex << i << FstName( fsts[ i ] );
|
||||||
if( !fst.filename[ 0 ] )//this one doesnt have a filename, it cant be used already
|
if( !fsts[ i ].filename[ 0 ] )//this one doesnt have a filename, it cant be used already
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( i == 0x17ff )
|
if( i == 0x17ff )
|
||||||
@ -1291,7 +1192,7 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui
|
|||||||
fsts[ entryNo ].sib = ret;
|
fsts[ entryNo ].sib = ret;
|
||||||
}
|
}
|
||||||
QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 );
|
QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 );
|
||||||
if( attr == 1 )
|
if( attr == NAND_FILE )
|
||||||
{
|
{
|
||||||
child->setIcon( 0, keyIcon );
|
child->setIcon( 0, keyIcon );
|
||||||
}
|
}
|
||||||
@ -1310,13 +1211,13 @@ bool NandBin::Delete( const QString &path )
|
|||||||
|
|
||||||
bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
||||||
{
|
{
|
||||||
qDebug() << "NandBin::DeleteItem" << item->text( 0 );
|
|
||||||
if( !item )
|
if( !item )
|
||||||
{
|
{
|
||||||
qWarning() << "cant delete a null item";
|
qWarning() << "cant delete a null item";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "NandBin::DeleteItem" << item->text( 0 );
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
quint16 idx = item->text( 1 ).toInt( &ok );//get the index of the entry to remove
|
quint16 idx = item->text( 1 ).toInt( &ok );//get the index of the entry to remove
|
||||||
if( !ok || idx > 0x17fe )
|
if( !ok || idx > 0x17fe )
|
||||||
@ -1341,7 +1242,24 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
|||||||
return false;//wtf
|
return false;//wtf
|
||||||
}
|
}
|
||||||
if( fsts[ parIdx ].sub == idx ) //this is the first item in the folder, point the parent to this items first sibling
|
if( fsts[ parIdx ].sub == idx ) //this is the first item in the folder, point the parent to this items first sibling
|
||||||
|
{
|
||||||
fsts[ parIdx ].sub = fsts[ idx ].sib;
|
fsts[ parIdx ].sub = fsts[ idx ].sib;
|
||||||
|
quint16 cnt = par->childCount();
|
||||||
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
if( par->child( i )->text( 0 ) == item->text( 0 ) )
|
||||||
|
{
|
||||||
|
pId = i;
|
||||||
|
//qDebug() << "found the item";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( i == cnt - 1 )//not found
|
||||||
|
{
|
||||||
|
qWarning() << "wtf 15" << pId << i << cnt;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else //point the previous entry to the next one
|
else //point the previous entry to the next one
|
||||||
{
|
{
|
||||||
@ -1382,28 +1300,22 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
int q = 0;
|
//int q = 0;
|
||||||
qDebug() << "deleting clusters of" << item->text( 0 ) << idx;
|
qDebug() << "deleting clusters of" << item->text( 0 ) << idx;
|
||||||
quint16 fat = fsts[ idx ].sub;//delete all this file's clusters
|
QList<quint16> toFree = GetFatsForFile( idx );
|
||||||
//fats.replace( fat, 0xfffe );
|
foreach( quint16 cl, toFree )
|
||||||
do
|
|
||||||
{
|
{
|
||||||
fats.replace( fat, 0xfffe );
|
fats.replace( cl, 0xfffe );
|
||||||
//qDebug() << "fat" << hex << fat;
|
|
||||||
fat = GetFAT( fat );
|
|
||||||
//fats.replace( fat, 0xfffe );
|
|
||||||
//qDebug() << "deleting cluster" << hex << fat << "from table";
|
|
||||||
q++;
|
|
||||||
}
|
}
|
||||||
while( fat < 0x17ff );
|
qDebug() << "delete loop done. freed" << toFree.size() << "clusters";
|
||||||
qDebug() << "delete loop done. freed" << q << "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
|
||||||
for( quint32 i = cnt - 1; i > 0; i-- )
|
qDebug() << cnt << "childern";
|
||||||
|
for( quint32 i = cnt; i > 0; i-- )
|
||||||
{
|
{
|
||||||
if( !DeleteItem( item->child( i - 1 ) ) )
|
if( !DeleteItem( item->child( i - 1 ) ) )
|
||||||
{
|
{
|
||||||
@ -1416,7 +1328,9 @@ 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
|
||||||
QTreeWidgetItem *d = par->takeChild( pId );
|
QTreeWidgetItem *d = par->takeChild( pId );
|
||||||
|
qDebug() << "deleting tree item" << d->text( 0 );
|
||||||
delete d;
|
delete d;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1425,12 +1339,18 @@ bool NandBin::SetData( const QString &path, const QByteArray data )
|
|||||||
{
|
{
|
||||||
QTreeWidgetItem *i = ItemFromPath( path );
|
QTreeWidgetItem *i = ItemFromPath( path );
|
||||||
if( !i )
|
if( !i )
|
||||||
|
{
|
||||||
|
qDebug() << "!item" << path;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
quint16 idx = i->text( 1 ).toInt( &ok );//find the entry
|
quint16 idx = i->text( 1 ).toInt( &ok );//find the entry
|
||||||
if( !ok || idx > 0x17fe )
|
if( !ok || idx > 0x17fe )
|
||||||
|
{
|
||||||
|
qDebug() << "out of range" << path;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return SetData( idx, data );
|
return SetData( idx, data );
|
||||||
}
|
}
|
||||||
@ -1438,8 +1358,12 @@ bool NandBin::SetData( const QString &path, const QByteArray data )
|
|||||||
bool NandBin::SetData( quint16 idx, const QByteArray data )
|
bool NandBin::SetData( quint16 idx, const QByteArray data )
|
||||||
{
|
{
|
||||||
fst_t fst = fsts[ idx ];
|
fst_t fst = fsts[ idx ];
|
||||||
|
qDebug() << "NandBin::SetData" << FstName( fst );
|
||||||
if( ( fst.attr & 3 ) != 1 )
|
if( ( fst.attr & 3 ) != 1 )
|
||||||
|
{
|
||||||
|
qDebug() << idx << "is a folder";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QList<quint16> fts = GetFatsForFile( idx ); //get the currently used fats and overwrite them. this doesnt serve much purpose, but it seems cleaner
|
QList<quint16> fts = GetFatsForFile( idx ); //get the currently used fats and overwrite them. this doesnt serve much purpose, but it seems cleaner
|
||||||
QByteArray pData = PaddedByteArray( data, 0x4000 );//actual data that must be written to the nand
|
QByteArray pData = PaddedByteArray( data, 0x4000 );//actual data that must be written to the nand
|
||||||
@ -1467,7 +1391,7 @@ bool NandBin::SetData( quint16 idx, const QByteArray data )
|
|||||||
qsrand( midnight.secsTo( QTime::currentTime() ) );
|
qsrand( midnight.secsTo( QTime::currentTime() ) );
|
||||||
|
|
||||||
//now grab the clusters that will be used from the list
|
//now grab the clusters that will be used from the list
|
||||||
qDebug() << "trying to find" << ( clCnt - fts.size() ) << "free clusters";
|
//qDebug() << "trying to find" << ( clCnt - fts.size() ) << "free clusters";
|
||||||
while( fts.size() < clCnt )
|
while( fts.size() < clCnt )
|
||||||
{
|
{
|
||||||
if( !freeClusters.size() )//avoid endless loop in case there are some clusters that should be free, but the spare data says theyre bad
|
if( !freeClusters.size() )//avoid endless loop in case there are some clusters that should be free, but the spare data says theyre bad
|
||||||
@ -1601,9 +1525,13 @@ bool NandBin::SetData( quint16 idx, const QByteArray data )
|
|||||||
|
|
||||||
QTreeWidgetItem *i = ItemFromEntry( idx, root );
|
QTreeWidgetItem *i = ItemFromEntry( idx, root );
|
||||||
if( !i )
|
if( !i )
|
||||||
|
{
|
||||||
|
qDebug() << "!ItemFromEntry";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
i->setText( 2, QString( "%1" ).arg( data.size(), 0, 16 ) );
|
i->setText( 2, QString( "%1" ).arg( data.size(), 0, 16 ) );
|
||||||
|
//f.flush();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1671,7 +1599,7 @@ bool NandBin::WriteMetaData()
|
|||||||
//qDebug() << "done adding shit" << hex << (quint32)b.pos();
|
//qDebug() << "done adding shit" << hex << (quint32)b.pos();
|
||||||
b.close();
|
b.close();
|
||||||
QByteArray hmR = spare.Get_hmac_meta( scl, nextSuperCluster );
|
QByteArray hmR = spare.Get_hmac_meta( scl, nextSuperCluster );
|
||||||
//qDebug() << "about to write the meta block" << hex << nextSuperCluster << nextClusterVersion << "to page" << (quint32)( nextSuperCluster * 8 );
|
qDebug() << "about to write the meta block" << hex << nextSuperCluster << nextClusterVersion << "to page" << (quint32)( nextSuperCluster * 8 );
|
||||||
|
|
||||||
for( quint8 i = 0; i < 0x10; i++ )
|
for( quint8 i = 0; i < 0x10; i++ )
|
||||||
{
|
{
|
||||||
@ -1685,6 +1613,9 @@ 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; //probably need to put some magic here in case the version wraps around back to 0
|
||||||
|
|
||||||
|
//make sure all the data is really written
|
||||||
|
f.flush();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ struct fst_t
|
|||||||
// class to deal with an encrypted wii nand dump
|
// class to deal with an encrypted wii nand dump
|
||||||
// basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree()
|
// basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree()
|
||||||
// extract files with GetFile()
|
// extract files with GetFile()
|
||||||
//! so far, all functions for writing to the nand are just dummies. i have only run a few test with them, but now actually used them to write to a nand
|
//! so far, all functions for writing to the nand are highly untested. it is not recommended to try to use this code productively!!
|
||||||
//! dont try to use them yet
|
//! you should verify anything written with this code before attempting to install it on you wii
|
||||||
|
|
||||||
//once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree()
|
//once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree()
|
||||||
class NandBin : public QObject
|
class NandBin : public QObject
|
||||||
@ -71,7 +71,6 @@ public:
|
|||||||
// 7 attr
|
// 7 attr
|
||||||
QTreeWidgetItem *GetTree();
|
QTreeWidgetItem *GetTree();
|
||||||
|
|
||||||
|
|
||||||
//extracts an item( and all its children ) to a directory
|
//extracts an item( and all its children ) to a directory
|
||||||
//this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns
|
//this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns
|
||||||
bool ExtractToDir( QTreeWidgetItem *item, const QString &path );
|
bool ExtractToDir( QTreeWidgetItem *item, const QString &path );
|
||||||
@ -130,6 +129,7 @@ public:
|
|||||||
bool SetData( const QString &path, const QByteArray data );
|
bool SetData( const QString &path, const QByteArray data );
|
||||||
|
|
||||||
//write the current changes to the metadata( if you dont do this, then none of the other stuff youve done wont be saved )
|
//write the current changes to the metadata( if you dont do this, then none of the other stuff youve done wont be saved )
|
||||||
|
// but at the same time, you probably dont need to overuse this. ( no need to write metadata every time you make a single change )
|
||||||
bool WriteMetaData();
|
bool WriteMetaData();
|
||||||
|
|
||||||
//functions to verify spare data
|
//functions to verify spare data
|
||||||
@ -207,10 +207,9 @@ private:
|
|||||||
QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL );
|
QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL );
|
||||||
QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL );
|
QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//connect to these to receive messages from this object
|
//connect to these to receive messages from this object
|
||||||
|
//so far, many errors are only outputting to qDebug() and qWarning().
|
||||||
void SendError( QString );
|
void SendError( QString );
|
||||||
void SendText( QString );
|
void SendText( QString );
|
||||||
};
|
};
|
||||||
|
@ -185,7 +185,7 @@ void fs_hmac_data( const unsigned char *data, quint32 uid, const unsigned char *
|
|||||||
|
|
||||||
QByteArray NandSpare::Get_hmac_data( const QByteArray cluster, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk )
|
QByteArray NandSpare::Get_hmac_data( const QByteArray cluster, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk )
|
||||||
{
|
{
|
||||||
//qDebug() << "NandSpare::Get_hmac_data" << hex << cluster.size() << uid << QString( (const char*)name ) << entry_n << x3 << blk;
|
//qDebug() << "NandSpare::Get_hmac_data" << hex << cluster.size() << uid << QString( QByteArray( (const char*)name, 12 ) ) << entry_n << x3 << blk;
|
||||||
if( hmacKey.size() != 0x14 || cluster.size() != 0x4000 )
|
if( hmacKey.size() != 0x14 || cluster.size() != 0x4000 )
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Setting.txt</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@ -96,7 +96,7 @@
|
|||||||
<item row="5" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QLineEdit" name="lineEdit_serno">
|
<widget class="QLineEdit" name="lineEdit_serno">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>123456789</string>
|
<string>622011873</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="maxLength">
|
<property name="maxLength">
|
||||||
<number>9</number>
|
<number>9</number>
|
||||||
|
@ -30,6 +30,7 @@ void Usage()
|
|||||||
qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters";
|
qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters";
|
||||||
qDebug() << " -spare calculate & compare ecc for all pages in the nand";
|
qDebug() << " -spare calculate & compare ecc for all pages in the nand";
|
||||||
qDebug() << " calculate & compare hmac signatures for all files and superblocks";
|
qDebug() << " calculate & compare hmac signatures for all files and superblocks";
|
||||||
|
qDebug() << " -all does all of the above";
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +341,7 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
//return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot
|
//return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot
|
||||||
break;
|
break;
|
||||||
case ERROR_RSA_FAKESIGNED:
|
case ERROR_RSA_FAKESIGNED:
|
||||||
// qDebug() << "\t" << it << "fakesigned";
|
qDebug() << "\t" << it << "fakesigned";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -408,13 +409,13 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
quint64 ios = t.IOS();
|
quint64 ios = t.IOS();
|
||||||
if( ios && !validIoses.contains( ios ) )
|
if( ios && !validIoses.contains( ios ) )
|
||||||
{
|
{
|
||||||
qDebug() << "the IOS for this title is not bootable";
|
qDebug() << "\tthe IOS for this title is not bootable\n\t" << TidTxt( ios ).insert( 8, "-" ) ;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
quint32 uid = uidM.GetUid( tid, false );
|
quint32 uid = uidM.GetUid( tid, false );
|
||||||
if( !uid )
|
if( !uid )
|
||||||
{
|
{
|
||||||
qDebug() << "this title has no UID entry";
|
qDebug() << "\tthis title has no UID entry";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,13 +630,13 @@ int main( int argc, char *argv[] )
|
|||||||
root = NULL;
|
root = NULL;
|
||||||
|
|
||||||
//these only serve to show info. no action is taken
|
//these only serve to show info. no action is taken
|
||||||
if( args.contains( "-boot", Qt::CaseInsensitive ) )
|
if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
|
||||||
{
|
{
|
||||||
qDebug() << "checking boot1 & 2...";
|
qDebug() << "checking boot1 & 2...";
|
||||||
ShowBootInfo( nand.Boot1Version(), nand.Boot2Infos() );
|
ShowBootInfo( nand.Boot1Version(), nand.Boot2Infos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( args.contains( "-fs", Qt::CaseInsensitive ) )
|
if( args.contains( "-fs", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
|
||||||
{
|
{
|
||||||
qDebug() << "checking uid.sys...";
|
qDebug() << "checking uid.sys...";
|
||||||
QByteArray ba = nand.GetData( "/sys/uid.sys" );
|
QByteArray ba = nand.GetData( "/sys/uid.sys" );
|
||||||
@ -662,13 +663,13 @@ int main( int argc, char *argv[] )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( args.contains( "-clInfo", Qt::CaseInsensitive ) )
|
if( args.contains( "-clInfo", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
|
||||||
{
|
{
|
||||||
qDebug() << "checking for lost clusters...";
|
qDebug() << "checking for lost clusters...";
|
||||||
CheckLostClusters();
|
CheckLostClusters();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( args.contains( "-spare", Qt::CaseInsensitive ) )
|
if( args.contains( "-spare", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
|
||||||
{
|
{
|
||||||
qDebug() << "verifying ecc...";
|
qDebug() << "verifying ecc...";
|
||||||
CheckEcc();
|
CheckEcc();
|
||||||
|
@ -22,7 +22,7 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M
|
|||||||
|
|
||||||
//TODO, really get these paths from settings
|
//TODO, really get these paths from settings
|
||||||
|
|
||||||
QString cachePath = "./NUS_cache";
|
QString cachePath = "../NUS_cache";
|
||||||
QString nandPath = "./dump";
|
QString nandPath = "./dump";
|
||||||
|
|
||||||
|
|
||||||
|
11
ohneschwanzenegger/main.cpp
Normal file
11
ohneschwanzenegger/main.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <QtGui/QApplication>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
662
ohneschwanzenegger/mainwindow.cpp
Normal file
662
ohneschwanzenegger/mainwindow.cpp
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
#include "mainwindow.h"
|
||||||
|
#include "newnandbin.h"
|
||||||
|
#include "ui_mainwindow.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 ), nand ( this )
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
nandInited = false;
|
||||||
|
root = NULL;
|
||||||
|
uidDirty = false;
|
||||||
|
sharedDirty = false;
|
||||||
|
nandDirty = false;
|
||||||
|
Wad::SetGlobalCert( QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) );
|
||||||
|
|
||||||
|
//connect to the nus object so we can respond to what it is saying with pretty stuff in the gui
|
||||||
|
connect( &nus, SIGNAL( SendDownloadProgress( int ) ), ui->progressBar_dl, SLOT( setValue( int ) ) );
|
||||||
|
connect( &nus, SIGNAL( SendTitleProgress( int ) ), ui->progressBar_title, SLOT( setValue( int ) ) );
|
||||||
|
connect( &nus, SIGNAL( SendTotalProgress( int ) ), ui->progressBar_whole, SLOT( setValue( int ) ) );
|
||||||
|
connect( &nus, SIGNAL( SendText( QString ) ), ui->statusBar, SLOT( showMessage( QString ) ) );
|
||||||
|
connect( &nus, SIGNAL( SendError( const QString &, NusJob ) ), this, SLOT( GetError( const QString &, NusJob ) ) );
|
||||||
|
connect( &nus, SIGNAL( SendDone() ), this, SLOT( NusIsDone() ) );
|
||||||
|
connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) );
|
||||||
|
|
||||||
|
//connect to the nand.bin to get text and crap from it
|
||||||
|
connect( &nand, SIGNAL( SendError( const QString & ) ), this, SLOT( GetError( const QString & ) ) );
|
||||||
|
connect( &nand, SIGNAL( SendText( QString ) ), ui->statusBar, SLOT( showMessage( QString ) ) );
|
||||||
|
|
||||||
|
//TODO, really get these paths from settings
|
||||||
|
|
||||||
|
QString cachePath = "../NUS_cache";
|
||||||
|
QString nandPath = "./testNand.bin";
|
||||||
|
//QString keyPath = "../keys.bin";
|
||||||
|
|
||||||
|
|
||||||
|
ui->lineEdit_cachePath->setText( cachePath );
|
||||||
|
ui->lineEdit_nandPath->setText( nandPath );
|
||||||
|
//ui->lineEdit_keys->setText( keyPath );
|
||||||
|
|
||||||
|
nus.SetCachePath( cachePath );
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
//some slots to respond to the NUS downloader
|
||||||
|
void MainWindow::GetError( const QString &message, NusJob job )
|
||||||
|
{
|
||||||
|
QString dataStuff = QString( "%1 items:" ).arg( job.data.size() );
|
||||||
|
for( int i = 0; i < job.data.size(); i++ )
|
||||||
|
dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) );
|
||||||
|
|
||||||
|
QString str = tr( "<b>Error getting title from NUS: %1</b>" ).arg( message );
|
||||||
|
QString j = QString( "NusJob( %1, %2, %3, %4 )<br>" )
|
||||||
|
.arg( job.tid, 16, 16, QChar( '0' ) )
|
||||||
|
.arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" )
|
||||||
|
.arg( dataStuff );
|
||||||
|
|
||||||
|
|
||||||
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
|
ui->plainTextEdit_log->appendHtml( j );
|
||||||
|
}
|
||||||
|
|
||||||
|
//get error from nand.bin
|
||||||
|
void MainWindow::GetError( const QString &message )
|
||||||
|
{
|
||||||
|
QString str = tr( "<b>Nand object Error: %1</b>" ).arg( message );
|
||||||
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::ShowMessage( const QString& mes )
|
||||||
|
{
|
||||||
|
QString str = mes + "<br>";
|
||||||
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::NusIsDone()
|
||||||
|
{
|
||||||
|
QString str = tr( "NUS object is done working<br>" );
|
||||||
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
|
ui->statusBar->showMessage( tr( "Done" ), 5000 );
|
||||||
|
|
||||||
|
//make sure there is a setting.txt
|
||||||
|
QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
||||||
|
if( !item )
|
||||||
|
{
|
||||||
|
QByteArray ba = SettingTxtDialog::Edit( this ); //call a dialog to create a new setting.txt
|
||||||
|
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand
|
||||||
|
{
|
||||||
|
quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ );
|
||||||
|
if( !r )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error creating setting.txt. maybe some folders are missing?</b>" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !nand.SetData( r, ba) )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error writing data for setting.txt.</b>" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nandDirty = true;
|
||||||
|
UpdateTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
||||||
|
if( nandDirty )
|
||||||
|
{
|
||||||
|
if( !FlushNand() )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error flushing nand. Maybe you used too much TP?</b>" );
|
||||||
|
}
|
||||||
|
nandDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::ReceiveTitleFromNus( NusJob job )
|
||||||
|
{
|
||||||
|
QString str = tr( "Received a completed download from NUS" );
|
||||||
|
//QString title = QString( "%1v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version );
|
||||||
|
|
||||||
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
|
|
||||||
|
//do something with the data we got
|
||||||
|
if( InstallNUSItem( job ) )
|
||||||
|
nandDirty = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//clicked the button to get a title
|
||||||
|
void MainWindow::on_pushButton_GetTitle_clicked()
|
||||||
|
{
|
||||||
|
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
bool wholeUpdate = false;
|
||||||
|
quint64 tid = 0;
|
||||||
|
quint32 ver = 0;
|
||||||
|
if( ui->lineEdit_tid->text().size() == 4 )
|
||||||
|
{
|
||||||
|
wholeUpdate = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 );
|
||||||
|
if( !ok )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number.</b>" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ver = TITLE_LATEST_VERSION;
|
||||||
|
if( !ui->lineEdit_version->text().isEmpty() )
|
||||||
|
{
|
||||||
|
ver = ui->lineEdit_version->text().toInt( &ok, 10 );
|
||||||
|
if( !ok )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number.</b>" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( ver > 0xffff )
|
||||||
|
{
|
||||||
|
ShowMessage( tr( "<b>Version %1 is too high. Max is 65535</b>" ).arg( ver ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//decide how we want nus to give us the title
|
||||||
|
bool decrypt = true;
|
||||||
|
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
||||||
|
if( wholeUpdate )
|
||||||
|
{
|
||||||
|
if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) )
|
||||||
|
{
|
||||||
|
ShowMessage( tr( "<b>I dont know the titles that were in the %1 update</b>" ).arg( ui->lineEdit_tid->text() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nus.Get( tid, decrypt, ver );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//search for a path to use as the nand basepath
|
||||||
|
void MainWindow::on_pushButton_nandPath_clicked()
|
||||||
|
{
|
||||||
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) );
|
||||||
|
if( f.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
ui->lineEdit_nandPath->setText( f );
|
||||||
|
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//nand-dump -> setting.txt
|
||||||
|
void MainWindow::on_actionSetting_txt_triggered()
|
||||||
|
{
|
||||||
|
if( !nandInited )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTreeWidgetItem *it = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
||||||
|
if( !it )
|
||||||
|
{
|
||||||
|
ShowMessage( tr( "<b>There is no setting.txt found in %1</b>" )
|
||||||
|
.arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray ba = nand.GetData( "/title/00000001/00000002/data/setting.txt" ); //read the current setting.txt
|
||||||
|
ba = SettingTxtDialog::Edit( this, ba ); //call a dialog to edit that existing file and store the result in the same bytearray
|
||||||
|
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand dump
|
||||||
|
nand.SetData( "/title/00000001/00000002/data/setting.txt", ba );
|
||||||
|
}
|
||||||
|
|
||||||
|
//nand-dump -> flush
|
||||||
|
void MainWindow::on_actionFlush_triggered()
|
||||||
|
{
|
||||||
|
if( !nandInited )
|
||||||
|
FlushNand();
|
||||||
|
}
|
||||||
|
|
||||||
|
//nand-dump -> ImportWad
|
||||||
|
void MainWindow::on_actionImportWad_triggered()
|
||||||
|
{
|
||||||
|
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
||||||
|
{
|
||||||
|
ShowMessage( tr( "<b>Error setting the basepath of the nand to %1</b>" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") );
|
||||||
|
|
||||||
|
if( fn.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray data = ReadFile( fn );
|
||||||
|
if( data.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Wad wad( data );
|
||||||
|
if( !wad.IsOk() )
|
||||||
|
{
|
||||||
|
ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//work smart, not hard... just turn the wad into a NUSJob and reused the same code to install it
|
||||||
|
NusJob job;
|
||||||
|
job.tid = wad.Tid();
|
||||||
|
job.data << wad.getTmd();
|
||||||
|
job.data << wad.getTik();
|
||||||
|
|
||||||
|
Tmd t( wad.getTmd() );
|
||||||
|
job.version = t.Version();
|
||||||
|
quint16 cnt = t.Count();
|
||||||
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
job.data << wad.Content( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
job.decrypt = true;
|
||||||
|
ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) );
|
||||||
|
InstallNUSItem( job );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionNew_nand_from_keys_triggered()
|
||||||
|
{
|
||||||
|
QString path = NewNandBin::GetNewNandPath( this );
|
||||||
|
if( path.isEmpty() )
|
||||||
|
return;
|
||||||
|
InitNand( path );
|
||||||
|
ui->lineEdit_nandPath->setText( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_initNand_clicked()
|
||||||
|
{
|
||||||
|
if( ui->lineEdit_nandPath->text().isEmpty() )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Please enter a path for nand.bin<\b>" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InitNand( ui->lineEdit_nandPath->text() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::InitNand( const QString &path )
|
||||||
|
{
|
||||||
|
nandInited = false;
|
||||||
|
sharedDirty = false;
|
||||||
|
nandDirty = false;
|
||||||
|
if( !nand.SetPath( path ) || !nand.InitNand() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !UpdateTree() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//setup the uid
|
||||||
|
QTreeWidgetItem *it = ItemFromPath( "/sys/uid.sys" );
|
||||||
|
if( !it )
|
||||||
|
{
|
||||||
|
uid.CreateNew( true );
|
||||||
|
if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error creating new uid.sys</b>" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uidDirty = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QByteArray ba = nand.GetData( "/sys/uid.sys" );
|
||||||
|
uid = UIDmap( ba );
|
||||||
|
}
|
||||||
|
//set up the shared map
|
||||||
|
it = ItemFromPath( "/shared1/content.map" );
|
||||||
|
if( !it )
|
||||||
|
{
|
||||||
|
if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
||||||
|
{
|
||||||
|
sharedDirty = true;
|
||||||
|
ShowMessage( "<b>Error creating new content.map</b>" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QByteArray ba = nand.GetData( "/shared1/content.map" );
|
||||||
|
shared = SharedContentMap( ba );
|
||||||
|
if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it
|
||||||
|
ShowMessage( "<b>Something about the shared map isnt right, but im using it anyways</b>" );
|
||||||
|
}
|
||||||
|
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
||||||
|
|
||||||
|
nandInited = true;
|
||||||
|
ShowMessage( "Set path to nand as " + path );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this one is kinda important
|
||||||
|
// it is in charge of writing the uid, content map, and all metadata to the nand.
|
||||||
|
//failing to do this will result in any changes not being applied
|
||||||
|
bool MainWindow::FlushNand()
|
||||||
|
{
|
||||||
|
//qDebug() << "MainWindow::FlushNand()";
|
||||||
|
bool r1 = true;
|
||||||
|
bool r2 = true;
|
||||||
|
if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) )
|
||||||
|
r1 = false;
|
||||||
|
else
|
||||||
|
uidDirty = false;
|
||||||
|
|
||||||
|
|
||||||
|
if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) )
|
||||||
|
r2 = false;
|
||||||
|
else
|
||||||
|
sharedDirty = false;
|
||||||
|
|
||||||
|
return ( nand.WriteMetaData() && r1 && r2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *MainWindow::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *MainWindow::ItemFromPath( const QString &path )
|
||||||
|
{
|
||||||
|
QTreeWidgetItem *item = root;
|
||||||
|
if( !path.startsWith( "/" ) || path.contains( "//" ))
|
||||||
|
{
|
||||||
|
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() << "ItemFromPath ->item not found" << path;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
slash = nextSlash + 1;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::PathFromItem( QTreeWidgetItem *item )
|
||||||
|
{
|
||||||
|
QString ret;
|
||||||
|
while( item )
|
||||||
|
{
|
||||||
|
ret.prepend( "/" + item->text( 0 ) );
|
||||||
|
item = item->parent();
|
||||||
|
if( item->text( 0 ) == "/" )// dont add the root
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::UpdateTree()
|
||||||
|
{
|
||||||
|
//set up the tree so we know what all is in the nand without asking for it every time
|
||||||
|
if( root )
|
||||||
|
delete root;
|
||||||
|
QTreeWidgetItem *r = nand.GetTree();
|
||||||
|
if( r->childCount() != 1 || r->child( 0 )->text( 0 ) != "/" )
|
||||||
|
{
|
||||||
|
ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
root = r->takeChild( 0 );
|
||||||
|
delete r;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 MainWindow::CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm )
|
||||||
|
{
|
||||||
|
// qDebug() << "MainWindow::CreateIfNeeded" << path;
|
||||||
|
QTreeWidgetItem *item = ItemFromPath( path );
|
||||||
|
if( !item )
|
||||||
|
{
|
||||||
|
quint16 ret = nand.CreateEntry( path, uid, gid, attr, user_perm, group_perm, other_perm );
|
||||||
|
if( ret && UpdateTree() )
|
||||||
|
return ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//TODO - if the item already exists, check that its attributes match the expected ones
|
||||||
|
return item->text( 1 ).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray hash )
|
||||||
|
{
|
||||||
|
//qDebug() << "MainWindow::InstallSharedContent";
|
||||||
|
QByteArray h;
|
||||||
|
if( hash.isEmpty() )
|
||||||
|
h = GetSha1( stuff );
|
||||||
|
else
|
||||||
|
h = hash;
|
||||||
|
|
||||||
|
QString cid = shared.GetAppFromHash( hash );
|
||||||
|
if( !cid.isEmpty() ) //this one is already installed
|
||||||
|
return true;
|
||||||
|
//qDebug() << "will create new";
|
||||||
|
|
||||||
|
//get next available cid in the shared map
|
||||||
|
cid = shared.GetNextEmptyCid();
|
||||||
|
shared.AddEntry( cid, h );
|
||||||
|
sharedDirty = true;
|
||||||
|
//qDebug() << "next cid" << cid;
|
||||||
|
|
||||||
|
//create the file
|
||||||
|
quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
|
if( !r )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//write the data to the file
|
||||||
|
return nand.SetData( r, stuff );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::InstallNUSItem( NusJob job )
|
||||||
|
{
|
||||||
|
QString title = QString( "%1 v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version );
|
||||||
|
qDebug() << "MainWindow::InstallNUSItem" << title;
|
||||||
|
|
||||||
|
quint16 r;
|
||||||
|
quint32 _uid;
|
||||||
|
quint16 _gid;
|
||||||
|
quint16 cnt;
|
||||||
|
bool deleted = false;
|
||||||
|
QTreeWidgetItem *content;
|
||||||
|
if( !job.tid || !job.data.size() > 2 )
|
||||||
|
{
|
||||||
|
qWarning() << "bad sizes";
|
||||||
|
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QString tid = QString( "%1" ).arg( job.tid, 16, 16, QChar( '0' ) );
|
||||||
|
QString upper = tid.left( 8 );
|
||||||
|
QString lower = tid.right( 8 );
|
||||||
|
|
||||||
|
Tmd t( job.data.takeFirst() );
|
||||||
|
Ticket ticket( job.data.takeFirst() );
|
||||||
|
if( t.Tid() != job.tid || ticket.Tid() != job.tid )
|
||||||
|
{
|
||||||
|
qWarning() << "bad tid";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
cnt = t.Count();
|
||||||
|
if( job.data.size() != cnt )
|
||||||
|
{
|
||||||
|
qWarning() << "content count";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
//qDebug() << "uidDirty" << uidDirty;
|
||||||
|
if( !uidDirty )
|
||||||
|
{
|
||||||
|
uidDirty = !uid.GetUid( job.tid, false );
|
||||||
|
}
|
||||||
|
//qDebug() << "uidDirty" << uidDirty;
|
||||||
|
_uid = uid.GetUid( job.tid );
|
||||||
|
|
||||||
|
_gid = t.Gid();
|
||||||
|
if( !_uid )
|
||||||
|
{
|
||||||
|
qWarning() << "no uid";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create all the folders
|
||||||
|
if( !CreateIfNeeded( "/ticket/" + upper, 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) )
|
||||||
|
{ qWarning() << "can't create ticket+upper folder";goto error;}
|
||||||
|
|
||||||
|
if( !CreateIfNeeded( "/title/" + upper, 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) )
|
||||||
|
{ qWarning() << "can't create title+upper folder";goto error;}
|
||||||
|
|
||||||
|
if( !CreateIfNeeded( "/title/" + upper + "/" + lower, 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) )
|
||||||
|
{ qWarning() << "can't create title+upper+lower folder";goto error;}
|
||||||
|
|
||||||
|
if( !CreateIfNeeded( "/title/" + upper + "/" + lower + "/content", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) )
|
||||||
|
{ qWarning() << "can't create content folder";goto error;}
|
||||||
|
|
||||||
|
if( !CreateIfNeeded( "/title/" + upper + "/" + lower + "/data", _uid, _gid, NAND_DIR, NAND_RW, 0, 0 ) )
|
||||||
|
{ qWarning() << "can't create data folder";goto error;}
|
||||||
|
|
||||||
|
//delete old tmd/.apps and whatever else in the content folder
|
||||||
|
content = ItemFromPath( "/title/" + upper + "/" + lower + "/content" );
|
||||||
|
cnt = content->childCount();
|
||||||
|
for ( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) )
|
||||||
|
{ qWarning() << "error deleting old title"; goto error; }
|
||||||
|
deleted = true;
|
||||||
|
}
|
||||||
|
if( deleted )
|
||||||
|
{
|
||||||
|
//nand.WriteMetaData();
|
||||||
|
UpdateTree();
|
||||||
|
ShowMessage( tr( "Deleted old TMD and private contents for\n%1" ).arg( title ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt = t.Count();
|
||||||
|
|
||||||
|
//install ticket
|
||||||
|
r = CreateIfNeeded( "/ticket/" + upper + "/" + lower + ".tik", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
|
if( !r )
|
||||||
|
{ qWarning() << "can't create ticket";goto error;}
|
||||||
|
if( !nand.SetData( r, ticket.Data() ) )
|
||||||
|
{ qWarning() << "can't write to ticket";goto error;}
|
||||||
|
|
||||||
|
//install tmd
|
||||||
|
r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/title.tmd", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
|
if( !r )
|
||||||
|
{ qWarning() << "can't create tmd";goto error;}
|
||||||
|
if( !nand.SetData( r, t.Data() ) )
|
||||||
|
{ qWarning() << "can't write to tmd";goto error;}
|
||||||
|
|
||||||
|
//install contents
|
||||||
|
//qDebug() << "will install" << cnt << "contents";
|
||||||
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
//qDebug() << "installing" << i;
|
||||||
|
//make sure the data is decrypted
|
||||||
|
QByteArray decData;
|
||||||
|
QByteArray hash;
|
||||||
|
if( job.decrypt )
|
||||||
|
{
|
||||||
|
decData = job.data.takeFirst();
|
||||||
|
if( (quint32)decData.size() != t.Size( i ) )
|
||||||
|
{
|
||||||
|
qDebug() << "wtf - size";
|
||||||
|
decData.resize( t.Size( i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//decrypt the data
|
||||||
|
QByteArray encData = job.data.takeFirst();
|
||||||
|
AesSetKey( ticket.DecryptedKey() );
|
||||||
|
decData = AesDecrypt( i, encData );
|
||||||
|
decData.resize( t.Size( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//check the hash
|
||||||
|
hash = GetSha1( decData );
|
||||||
|
if( hash != t.Hash( i ) )
|
||||||
|
{
|
||||||
|
qWarning() << "hash" << i << "\n" << hash.toHex() << "\n" << t.Hash( i ).toHex();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//install the content
|
||||||
|
if( t.Type( i ) == 1 )//private
|
||||||
|
{
|
||||||
|
r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/" + t.Cid( i ) + ".app" , 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
|
if( !r )
|
||||||
|
{
|
||||||
|
qWarning() << "cant create content" << i;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ( !nand.SetData( r, decData ) )
|
||||||
|
{
|
||||||
|
qWarning() << "cant write content" << i;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( t.Type( i ) == 0x8001 )//shared
|
||||||
|
{
|
||||||
|
if ( !InstallSharedContent( decData, hash ) )
|
||||||
|
{
|
||||||
|
qWarning() << "error installing shared" << i << hash.toHex();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "type" << hex << t.Type( i );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "done installing";
|
||||||
|
ShowMessage( "Installed title " + title + " to nand" );
|
||||||
|
|
||||||
|
//nand.Delete( "/title/" + upper );
|
||||||
|
//UpdateTree();
|
||||||
|
return true;
|
||||||
|
error:
|
||||||
|
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//help -> about
|
||||||
|
void MainWindow::on_actionAbout_triggered()
|
||||||
|
{
|
||||||
|
QString txt = tr( "This is an example program from WiiQt. It is designed to write titles to a nand.bin and even create one from scratch."
|
||||||
|
"<br><br>PLEASE BE AWARE, THIS IS NOT VERY WELL TESTED AND AS OF RIGHT NOW."
|
||||||
|
" IT SHOULD ONLY BE USED BY PEOPLE THAT KNOW HOW TO VERIFY THE FILES IT PRODUCES. AND HAVE A WAY TO FIX A BRICKED WII SHOULD THIS PROGRAM HAVE BUGS"
|
||||||
|
"<br><br>YOU HAVE BEEN WARNED"
|
||||||
|
"<br>giantpune" );
|
||||||
|
QMessageBox::critical( this, tr( "About" ), txt );
|
||||||
|
}
|
67
ohneschwanzenegger/mainwindow.h
Normal file
67
ohneschwanzenegger/mainwindow.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include "../WiiQt/includes.h"
|
||||||
|
#include "../WiiQt/nusdownloader.h"
|
||||||
|
#include "../WiiQt/nandbin.h"
|
||||||
|
#include "../WiiQt/uidmap.h"
|
||||||
|
#include "../WiiQt/sharedcontentmap.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow( QWidget *parent = 0 );
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
QTreeWidgetItem *root;
|
||||||
|
bool nandInited;
|
||||||
|
bool uidDirty;
|
||||||
|
bool sharedDirty;
|
||||||
|
bool nandDirty;
|
||||||
|
|
||||||
|
NusDownloader nus;
|
||||||
|
NandBin nand;
|
||||||
|
UIDmap uid;
|
||||||
|
SharedContentMap shared;
|
||||||
|
bool FlushNand();
|
||||||
|
|
||||||
|
void ShowMessage( const QString& mes );
|
||||||
|
|
||||||
|
bool InitNand( const QString &path );
|
||||||
|
bool UpdateTree();
|
||||||
|
|
||||||
|
QString PathFromItem( QTreeWidgetItem *item );
|
||||||
|
QTreeWidgetItem *ItemFromPath( const QString &path );
|
||||||
|
QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent );
|
||||||
|
|
||||||
|
bool InstallNUSItem( NusJob job );
|
||||||
|
quint16 CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm );
|
||||||
|
bool InstallSharedContent( const QByteArray stuff, const QByteArray hash = QByteArray() );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
//slots for getting info from the NUS downloader
|
||||||
|
void GetError( const QString &message, NusJob job );
|
||||||
|
void GetError( const QString &message );
|
||||||
|
void NusIsDone();
|
||||||
|
void ReceiveTitleFromNus( NusJob job );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_actionAbout_triggered();
|
||||||
|
void on_pushButton_initNand_clicked();
|
||||||
|
void on_actionNew_nand_from_keys_triggered();
|
||||||
|
void on_actionFlush_triggered();
|
||||||
|
void on_actionSetting_txt_triggered();
|
||||||
|
void on_actionImportWad_triggered();
|
||||||
|
void on_pushButton_nandPath_clicked();
|
||||||
|
void on_pushButton_GetTitle_clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
237
ohneschwanzenegger/mainwindow.ui
Normal file
237
ohneschwanzenegger/mainwindow.ui
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>654</width>
|
||||||
|
<height>507</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>NUS NandBuilder</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="margin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_tid">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4_version">
|
||||||
|
<property name="text">
|
||||||
|
<string>v</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_version">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>107</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_GetTitle">
|
||||||
|
<property name="text">
|
||||||
|
<string>Get It!</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_cachePath"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_CachePathBrowse">
|
||||||
|
<property name="text">
|
||||||
|
<string>Local Cache</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_progDl">
|
||||||
|
<property name="text">
|
||||||
|
<string>Download</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QProgressBar" name="progressBar_dl">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_progTitle">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QProgressBar" name="progressBar_title">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_progTotal">
|
||||||
|
<property name="text">
|
||||||
|
<string>Total</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QProgressBar" name="progressBar_whole">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>nand.bin</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_nandPath">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_nandPath">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_initNand">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Init Nand</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="plainTextEdit_log"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>654</width>
|
||||||
|
<height>27</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuNand_Dump">
|
||||||
|
<property name="title">
|
||||||
|
<string>Nand Dump</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionSetting_txt"/>
|
||||||
|
<addaction name="actionFlush"/>
|
||||||
|
<addaction name="actionImportWad"/>
|
||||||
|
<addaction name="actionNew_nand_from_keys"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuNand_Dump"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="mainToolBar">
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<action name="actionSetting_txt">
|
||||||
|
<property name="text">
|
||||||
|
<string>Setting.txt...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFlush">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flush</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionImportWad">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import Wad</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_nand_from_keys">
|
||||||
|
<property name="text">
|
||||||
|
<string>New nand...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="text">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
123
ohneschwanzenegger/newnandbin.cpp
Normal file
123
ohneschwanzenegger/newnandbin.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "newnandbin.h"
|
||||||
|
#include "ui_newnandbin.h"
|
||||||
|
#include "../WiiQt/tools.h"
|
||||||
|
|
||||||
|
NewNandBin::NewNandBin( QWidget *parent, QList<quint16> badBlocks ) : QDialog(parent), ui(new Ui::NewNandBin), nand( this )
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
foreach( quint16 block, badBlocks )
|
||||||
|
{
|
||||||
|
QString txt = QString( "%1" ).arg( block );
|
||||||
|
if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() )
|
||||||
|
ui->listWidget_badBlocks->addItem( txt );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewNandBin::~NewNandBin()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewNandBin::on_pushButton_keys_clicked()
|
||||||
|
{
|
||||||
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ) );
|
||||||
|
if( f.isEmpty() )
|
||||||
|
return;
|
||||||
|
ui->lineEdit_keys->setText( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewNandBin::on_pushButton_boot_clicked()
|
||||||
|
{
|
||||||
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ) );
|
||||||
|
if( f.isEmpty() )
|
||||||
|
return;
|
||||||
|
ui->lineEdit_boot->setText( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewNandBin::on_pushButton_dest_clicked()
|
||||||
|
{
|
||||||
|
QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ) );
|
||||||
|
if( f.isEmpty() )
|
||||||
|
return;
|
||||||
|
ui->lineEdit_dest->setText( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<quint16> NewNandBin::BadBlocks()
|
||||||
|
{
|
||||||
|
QList<quint16> ret;
|
||||||
|
quint16 cnt = ui->listWidget_badBlocks->count();
|
||||||
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok );
|
||||||
|
if( ok )
|
||||||
|
ret << num;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewNandBin::on_pushButton_bb_add_clicked()
|
||||||
|
{
|
||||||
|
quint16 val = ui->spinBox->value();
|
||||||
|
if( !BadBlocks().contains( val ) )
|
||||||
|
{
|
||||||
|
ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) );
|
||||||
|
//QListWidgetItem *i = new QListWidgetItem( QString( "%1" ).arg( val ), ui->listWidget_badBlocks );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewNandBin::on_pushButton_bb_rm_clicked()
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items = ui->listWidget_badBlocks->selectedItems();
|
||||||
|
foreach( QListWidgetItem *item, items )
|
||||||
|
{
|
||||||
|
ui->listWidget_badBlocks->removeItemWidget( item );
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ok clicked
|
||||||
|
void NewNandBin::on_buttonBox_accepted()
|
||||||
|
{
|
||||||
|
if( ui->lineEdit_keys->text().isEmpty() || ui->lineEdit_boot->text().isEmpty() || ui->lineEdit_dest->text().isEmpty() )
|
||||||
|
{
|
||||||
|
QMessageBox::warning( this, tr( "Error" ), tr( "Required feilds are empty" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray keys = ReadFile( ui->lineEdit_keys->text() );
|
||||||
|
QByteArray boots = ReadFile( ui->lineEdit_boot->text() );
|
||||||
|
if( keys.size() != 0x400 || boots.size() != 0x108000 )
|
||||||
|
{
|
||||||
|
QMessageBox::warning( this, tr( "Error" ), tr( "The keys or boot1/2 is not correct" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( !nand.CreateNew( ui->lineEdit_dest->text(), keys, boots, BadBlocks() ) )
|
||||||
|
{
|
||||||
|
qDebug() << "error creating nand.bin";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//qDebug() << "created nand, trying to add default entries";
|
||||||
|
if( !nand.CreateEntry( "/sys", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|
|| !nand.CreateEntry( "/ticket", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|
|| !nand.CreateEntry( "/title", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ )
|
||||||
|
|| !nand.CreateEntry( "/shared1", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|
|| !nand.CreateEntry( "/shared2", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|
|| !nand.CreateEntry( "/import", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|
|| !nand.CreateEntry( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|
|| !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|
|| !nand.WriteMetaData() )
|
||||||
|
{
|
||||||
|
qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating the new nand";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ui->lineEdit_dest->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NewNandBin::GetNewNandPath( QWidget *parent, QList<quint16> badBlocks )
|
||||||
|
{
|
||||||
|
NewNandBin d( parent, badBlocks );
|
||||||
|
if( !d.exec() )
|
||||||
|
return QString();
|
||||||
|
return d.ret;
|
||||||
|
}
|
38
ohneschwanzenegger/newnandbin.h
Normal file
38
ohneschwanzenegger/newnandbin.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef NEWNANDBIN_H
|
||||||
|
#define NEWNANDBIN_H
|
||||||
|
|
||||||
|
#include "../WiiQt/includes.h"
|
||||||
|
#include "../WiiQt/nandbin.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class NewNandBin;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NewNandBin : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NewNandBin( QWidget *parent = 0, QList<quint16>badBlocks = QList<quint16>() );
|
||||||
|
~NewNandBin();
|
||||||
|
|
||||||
|
static QString GetNewNandPath( QWidget *parent = 0, QList<quint16>badBlocks = QList<quint16>() );
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::NewNandBin *ui;
|
||||||
|
QList<quint16> BadBlocks();
|
||||||
|
|
||||||
|
NandBin nand;
|
||||||
|
|
||||||
|
QString ret;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_buttonBox_accepted();
|
||||||
|
void on_pushButton_bb_rm_clicked();
|
||||||
|
void on_pushButton_bb_add_clicked();
|
||||||
|
void on_pushButton_dest_clicked();
|
||||||
|
void on_pushButton_boot_clicked();
|
||||||
|
void on_pushButton_keys_clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NEWNANDBIN_H
|
234
ohneschwanzenegger/newnandbin.ui
Normal file
234
ohneschwanzenegger/newnandbin.ui
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>NewNandBin</class>
|
||||||
|
<widget class="QDialog" name="NewNandBin">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>427</width>
|
||||||
|
<height>290</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>New Nand</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPushButton" name="pushButton_keys">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keys</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_keys">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QPushButton" name="pushButton_boot">
|
||||||
|
<property name="text">
|
||||||
|
<string>Boot 1 && 2</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_boot">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QPushButton" name="pushButton_dest">
|
||||||
|
<property name="text">
|
||||||
|
<string>Destination</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_dest">
|
||||||
|
<property name="text">
|
||||||
|
<string>./testNand.bin</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox_bad">
|
||||||
|
<property name="title">
|
||||||
|
<string>Bad Blocks</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="margin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>90</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>4079</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_bb_add">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>37</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>>></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_bb_rm">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>37</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><<</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listWidget_badBlocks">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::RightToLeft</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>149</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>NewNandBin</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>NewNandBin</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
49
ohneschwanzenegger/refleurii.pro
Normal file
49
ohneschwanzenegger/refleurii.pro
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2010-12-02T23:30:12
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT += core gui\
|
||||||
|
network
|
||||||
|
|
||||||
|
TARGET = ohneschwanzenegger
|
||||||
|
TEMPLATE = app
|
||||||
|
DEFINES += NAND_BIN_CAN_WRITE
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES += main.cpp\
|
||||||
|
mainwindow.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 \
|
||||||
|
newnandbin.cpp \
|
||||||
|
../WiiQt/nandbin.cpp \
|
||||||
|
../WiiQt/nandspare.cpp\
|
||||||
|
../WiiQt/blocks0to7.cpp
|
||||||
|
|
||||||
|
HEADERS += mainwindow.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 \
|
||||||
|
newnandbin.h \
|
||||||
|
../WiiQt/nandbin.h \
|
||||||
|
../WiiQt/nandspare.h\
|
||||||
|
../WiiQt/blocks0to7.h
|
||||||
|
|
||||||
|
FORMS += mainwindow.ui \
|
||||||
|
../WiiQt/settingtxtdialog.ui \
|
||||||
|
newnandbin.ui
|
Loading…
Reference in New Issue
Block a user