mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-12-26 04:41: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()
|
||||
{
|
||||
if( f.isOpen() )
|
||||
{
|
||||
f.flush();
|
||||
f.close();
|
||||
}
|
||||
|
||||
if( root )
|
||||
delete root;
|
||||
@ -147,6 +150,7 @@ bool NandBin::CreateNew( const QString &path, QByteArray keys, QByteArray first8
|
||||
|
||||
QTreeWidgetItem *NandBin::GetTree()
|
||||
{
|
||||
//qDebug() << "NandBin::GetTree()";
|
||||
return root->clone();
|
||||
}
|
||||
|
||||
@ -371,7 +375,17 @@ bool NandBin::InitNand( QIcon dirs, QIcon files )
|
||||
|
||||
root = new QTreeWidgetItem( QStringList() << nandPath );
|
||||
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
|
||||
QList<QByteArray>blocks;
|
||||
@ -390,120 +404,10 @@ bool NandBin::InitNand( QIcon dirs, QIcon files )
|
||||
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 ) )
|
||||
return false;
|
||||
|
||||
ShowInfo();
|
||||
//ShowInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -764,11 +668,7 @@ quint16 NandBin::GetFAT( quint16 fat_entry )
|
||||
{
|
||||
if( fstInited )
|
||||
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;
|
||||
|
||||
// location in fat of cluster chain
|
||||
@ -1127,7 +1027,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr
|
||||
QByteArray spareData( 0x40, '\0' );
|
||||
quint8* sp = (quint8*)spareData.data();
|
||||
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
|
||||
if( !hmac.isEmpty() )
|
||||
{
|
||||
@ -1138,7 +1038,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr
|
||||
}
|
||||
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 ) )
|
||||
@ -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 );
|
||||
|
||||
quint32 i;
|
||||
//qDebug() << "looking for first empty node";
|
||||
for( i = 1; i < 0x17ff; i++ )//cant be entry 0 because that is the root
|
||||
{
|
||||
fst_t fst = fsts[ i ];
|
||||
if( !fst.filename[ 0 ] )//this one doesnt have a filename, it cant be used already
|
||||
//qDebug() << hex << i << FstName( fsts[ i ] );
|
||||
if( !fsts[ i ].filename[ 0 ] )//this one doesnt have a filename, it cant be used already
|
||||
break;
|
||||
}
|
||||
if( i == 0x17ff )
|
||||
@ -1291,7 +1192,7 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui
|
||||
fsts[ entryNo ].sib = ret;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
@ -1310,13 +1211,13 @@ bool NandBin::Delete( const QString &path )
|
||||
|
||||
bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
||||
{
|
||||
qDebug() << "NandBin::DeleteItem" << item->text( 0 );
|
||||
if( !item )
|
||||
{
|
||||
qWarning() << "cant delete a null item";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "NandBin::DeleteItem" << item->text( 0 );
|
||||
bool ok = false;
|
||||
quint16 idx = item->text( 1 ).toInt( &ok );//get the index of the entry to remove
|
||||
if( !ok || idx > 0x17fe )
|
||||
@ -1341,7 +1242,24 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
||||
return false;//wtf
|
||||
}
|
||||
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;
|
||||
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
|
||||
{
|
||||
@ -1382,28 +1300,22 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
int q = 0;
|
||||
//int q = 0;
|
||||
qDebug() << "deleting clusters of" << item->text( 0 ) << idx;
|
||||
quint16 fat = fsts[ idx ].sub;//delete all this file's clusters
|
||||
//fats.replace( fat, 0xfffe );
|
||||
do
|
||||
QList<quint16> toFree = GetFatsForFile( idx );
|
||||
foreach( quint16 cl, toFree )
|
||||
{
|
||||
fats.replace( fat, 0xfffe );
|
||||
//qDebug() << "fat" << hex << fat;
|
||||
fat = GetFAT( fat );
|
||||
//fats.replace( fat, 0xfffe );
|
||||
//qDebug() << "deleting cluster" << hex << fat << "from table";
|
||||
q++;
|
||||
fats.replace( cl, 0xfffe );
|
||||
}
|
||||
while( fat < 0x17ff );
|
||||
qDebug() << "delete loop done. freed" << q << "clusters";
|
||||
qDebug() << "delete loop done. freed" << toFree.size() << "clusters";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qDebug() << "deleting children of" << item->text( 0 );
|
||||
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 ) ) )
|
||||
{
|
||||
@ -1416,7 +1328,9 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item )
|
||||
|
||||
}
|
||||
memset( &fsts[ idx ], 0, sizeof( fst_t ) ); //clear this entry
|
||||
fsts[ idx ].fst_pos = idx; //reset this
|
||||
QTreeWidgetItem *d = par->takeChild( pId );
|
||||
qDebug() << "deleting tree item" << d->text( 0 );
|
||||
delete d;
|
||||
return true;
|
||||
}
|
||||
@ -1425,12 +1339,18 @@ bool NandBin::SetData( const QString &path, const QByteArray data )
|
||||
{
|
||||
QTreeWidgetItem *i = ItemFromPath( path );
|
||||
if( !i )
|
||||
{
|
||||
qDebug() << "!item" << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
quint16 idx = i->text( 1 ).toInt( &ok );//find the entry
|
||||
if( !ok || idx > 0x17fe )
|
||||
{
|
||||
qDebug() << "out of range" << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
fst_t fst = fsts[ idx ];
|
||||
qDebug() << "NandBin::SetData" << FstName( fst );
|
||||
if( ( fst.attr & 3 ) != 1 )
|
||||
{
|
||||
qDebug() << idx << "is a folder";
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
@ -1467,7 +1391,7 @@ bool NandBin::SetData( quint16 idx, const QByteArray data )
|
||||
qsrand( midnight.secsTo( QTime::currentTime() ) );
|
||||
|
||||
//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 )
|
||||
{
|
||||
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 );
|
||||
if( !i )
|
||||
{
|
||||
qDebug() << "!ItemFromEntry";
|
||||
return false;
|
||||
}
|
||||
|
||||
i->setText( 2, QString( "%1" ).arg( data.size(), 0, 16 ) );
|
||||
//f.flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1671,7 +1599,7 @@ bool NandBin::WriteMetaData()
|
||||
//qDebug() << "done adding shit" << hex << (quint32)b.pos();
|
||||
b.close();
|
||||
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++ )
|
||||
{
|
||||
@ -1685,6 +1613,9 @@ bool NandBin::WriteMetaData()
|
||||
currentSuperCluster = nextSuperCluster;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,8 @@ 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()
|
||||
//! 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
|
||||
//! dont try to use them yet
|
||||
//! so far, all functions for writing to the nand are highly untested. it is not recommended to try to use this code productively!!
|
||||
//! 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()
|
||||
class NandBin : public QObject
|
||||
@ -71,7 +71,6 @@ public:
|
||||
// 7 attr
|
||||
QTreeWidgetItem *GetTree();
|
||||
|
||||
|
||||
//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
|
||||
bool ExtractToDir( QTreeWidgetItem *item, const QString &path );
|
||||
@ -130,6 +129,7 @@ public:
|
||||
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 )
|
||||
// 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();
|
||||
|
||||
//functions to verify spare data
|
||||
@ -207,10 +207,9 @@ private:
|
||||
QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL );
|
||||
QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL );
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
//connect to these to receive messages from this object
|
||||
//so far, many errors are only outputting to qDebug() and qWarning().
|
||||
void SendError( 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 )
|
||||
{
|
||||
//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 )
|
||||
return QByteArray();
|
||||
|
||||
|
@ -616,7 +616,7 @@ QMap< quint64, quint16 > NusDownloader::List31j()
|
||||
titles.insert( 0x100000022ull, 1039 );//34v1039
|
||||
titles.insert( 0x100000023ull, 1040 );//35v1040
|
||||
titles.insert( 0x100000024ull, 1042 );//36v1042
|
||||
//titles.insert( 0x100000025ull, 2070 );//37v2070//3.1u has this one but not 3.1j??
|
||||
//titles.insert( 0x100000025ull, 2070 );//37v2070 //3.1u has this one but not 3.1j??
|
||||
titles.insert( 0x1000248415941ull, 0x1 );//photo2v1
|
||||
titles.insert( 0x1000848414B4aull, 0 );//EULA - HAKJ
|
||||
titles.insert( 0x100024841464aull, 0x7 );// forcast v7 HAFJ
|
||||
|
@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>Setting.txt</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
@ -96,7 +96,7 @@
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_serno">
|
||||
<property name="text">
|
||||
<string>123456789</string>
|
||||
<string>622011873</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<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() << " -spare calculate & compare ecc for all pages in the nand";
|
||||
qDebug() << " calculate & compare hmac signatures for all files and superblocks";
|
||||
qDebug() << " -all does all of the above";
|
||||
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
|
||||
break;
|
||||
case ERROR_RSA_FAKESIGNED:
|
||||
// qDebug() << "\t" << it << "fakesigned";
|
||||
qDebug() << "\t" << it << "fakesigned";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -408,13 +409,13 @@ bool CheckTitleIntegrity( quint64 tid )
|
||||
quint64 ios = t.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;
|
||||
}
|
||||
quint32 uid = uidM.GetUid( tid, false );
|
||||
if( !uid )
|
||||
{
|
||||
qDebug() << "this title has no UID entry";
|
||||
qDebug() << "\tthis title has no UID entry";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -629,13 +630,13 @@ int main( int argc, char *argv[] )
|
||||
root = NULL;
|
||||
|
||||
//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...";
|
||||
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...";
|
||||
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...";
|
||||
CheckLostClusters();
|
||||
}
|
||||
|
||||
if( args.contains( "-spare", Qt::CaseInsensitive ) )
|
||||
if( args.contains( "-spare", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
|
||||
{
|
||||
qDebug() << "verifying ecc...";
|
||||
CheckEcc();
|
||||
|
@ -22,7 +22,7 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M
|
||||
|
||||
//TODO, really get these paths from settings
|
||||
|
||||
QString cachePath = "./NUS_cache";
|
||||
QString cachePath = "../NUS_cache";
|
||||
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