diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp
index 5c46b26..4939733 100755
--- a/WiiQt/nandbin.cpp
+++ b/WiiQt/nandbin.cpp
@@ -90,6 +90,9 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
fats.clear();
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
+ for( quint16 i = 0; i < 0x17ff; i++ )
+ fsts[ i ].fst_pos = i;
+
//reserve blocks 0 - 7
for( quint16 i = 0; i < 0x40; i++ )
{
@@ -1193,7 +1196,12 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui
if( !ret )
return 0;
- fsts[ entryNo ].sib = ret;
+ //method 1: this works, and the nand is bootable. but doesnt mimic the IOS FS driver. ( my entries appear in reversed order when walking the FS )
+ //fsts[ entryNo ].sib = ret;
+
+ //method 2: trying to mimic the IOS FS driver ( insert new entries at the start of the chain, instead of the end )
+ fsts[ ret ].sib = fsts[ parIdx ].sub;
+ fsts[ parIdx ].sub = ret;
}
QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 );
if( attr == NAND_FILE )
diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp
index 3090956..1d23433 100644
--- a/ohneschwanzenegger/mainwindow.cpp
+++ b/ohneschwanzenegger/mainwindow.cpp
@@ -56,13 +56,13 @@ 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( ' ' ) );
+ dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) );
QString str = tr( "Error getting title from NUS: %1" ).arg( message );
QString j = QString( "NusJob( %1, %2, %3, %4 )
" )
- .arg( job.tid, 16, 16, QChar( '0' ) )
- .arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" )
- .arg( dataStuff );
+ .arg( job.tid, 16, 16, QChar( '0' ) )
+ .arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" )
+ .arg( dataStuff );
ui->plainTextEdit_log->appendHtml( str );
@@ -92,44 +92,44 @@ void MainWindow::NusIsDone()
QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
if( !item )
{
- quint8 reg = SETTING_TXT_UNK;
- if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
- reg = SETTING_TXT_PAL;
- if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
- reg = SETTING_TXT_JAP;
- if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
- reg = SETTING_TXT_KOR;
- QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //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( "Error creating setting.txt. maybe some folders are missing?" );
- }
- else
- {
- if( !nand.SetData( r, ba) )
+ quint8 reg = SETTING_TXT_UNK;
+ if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
+ reg = SETTING_TXT_PAL;
+ if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
+ reg = SETTING_TXT_JAP;
+ if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
+ reg = SETTING_TXT_KOR;
+ QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //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
{
- ShowMessage( "Error writing data for setting.txt." );
+ quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ );
+ if( !r )
+ {
+ ShowMessage( "Error creating setting.txt. maybe some folders are missing?" );
+ }
+ else
+ {
+ if( !nand.SetData( r, ba) )
+ {
+ ShowMessage( "Error writing data for setting.txt." );
+ }
+ else
+ {
+ nandDirty = true;
+ UpdateTree();
+ }
+ }
}
- else
- {
- nandDirty = true;
- UpdateTree();
- }
- }
- }
}
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
if( nandDirty )
{
- if( !FlushNand() )
- {
- ShowMessage( "Error flushing nand. Maybe you used too much TP?" );
- }
- nandDirty = false;
+ if( !FlushNand() )
+ {
+ ShowMessage( "Error flushing nand. Maybe you used too much TP?" );
+ }
+ nandDirty = false;
}
}
@@ -142,7 +142,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job )
//do something with the data we got
if( InstallNUSItem( job ) )
- nandDirty = true;
+ nandDirty = true;
}
@@ -150,7 +150,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job )
void MainWindow::on_pushButton_GetTitle_clicked()
{
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
- return;
+ return;
bool ok = false;
bool wholeUpdate = false;
@@ -158,46 +158,46 @@ void MainWindow::on_pushButton_GetTitle_clicked()
quint32 ver = 0;
if( ui->lineEdit_tid->text().size() == 4 )
{
- wholeUpdate = true;
+ wholeUpdate = true;
}
else
{
- tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 );
- if( !ok )
- {
- ShowMessage( "Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number." );
- return;
- }
- ver = TITLE_LATEST_VERSION;
- if( !ui->lineEdit_version->text().isEmpty() )
- {
- ver = ui->lineEdit_version->text().toInt( &ok, 10 );
- if( !ok )
- {
- ShowMessage( "Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number." );
- return;
- }
- if( ver > 0xffff )
- {
- ShowMessage( tr( "Version %1 is too high. Max is 65535" ).arg( ver ) );
- return;
- }
- }
+ tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 );
+ if( !ok )
+ {
+ ShowMessage( "Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number." );
+ return;
+ }
+ ver = TITLE_LATEST_VERSION;
+ if( !ui->lineEdit_version->text().isEmpty() )
+ {
+ ver = ui->lineEdit_version->text().toInt( &ok, 10 );
+ if( !ok )
+ {
+ ShowMessage( "Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number." );
+ return;
+ }
+ if( ver > 0xffff )
+ {
+ ShowMessage( tr( "Version %1 is too high. Max is 65535" ).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( "I dont know the titles that were in the %1 update" ).arg( ui->lineEdit_tid->text() ) );
- return;
- }
+ if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) )
+ {
+ ShowMessage( tr( "I dont know the titles that were in the %1 update" ).arg( ui->lineEdit_tid->text() ) );
+ return;
+ }
}
else
{
- nus.Get( tid, decrypt, ver );
+ nus.Get( tid, decrypt, ver );
}
}
@@ -206,7 +206,7 @@ void MainWindow::on_pushButton_nandPath_clicked()
{
QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) );
if( f.isEmpty() )
- return;
+ return;
ui->lineEdit_nandPath->setText( f );
}
@@ -215,7 +215,7 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked()
{
QString f = QFileDialog::getExistingDirectory( this, tr( "Select NUS Cache base folder" ) );
if( f.isEmpty() )
- return;
+ return;
ui->lineEdit_cachePath->setText( f );
nus.SetCachePath( ui->lineEdit_cachePath->text() );
@@ -225,26 +225,26 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked()
void MainWindow::on_actionSetting_txt_triggered()
{
if( !nandInited )
- return;
+ return;
QTreeWidgetItem *it = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
if( !it )
{
- ShowMessage( tr( "There is no setting.txt found in %1" )
- .arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
- return;
+ ShowMessage( tr( "There is no setting.txt found in %1" )
+ .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.SetData( "/title/00000001/00000002/data/setting.txt", ba );
}
//nand-dump -> flush
void MainWindow::on_actionFlush_triggered()
{
if( !nandInited )
- FlushNand();
+ FlushNand();
}
//nand-dump -> ImportWad
@@ -252,23 +252,23 @@ void MainWindow::on_actionImportWad_triggered()
{
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
{
- ShowMessage( tr( "Error setting the basepath of the nand to %1" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
- return;
+ ShowMessage( tr( "Error setting the basepath of the nand to %1" ).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;
+ return;
QByteArray data = ReadFile( fn );
if( data.isEmpty() )
- return;
+ return;
Wad wad( data );
if( !wad.IsOk() )
{
- ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) );
- return;
+ 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
@@ -282,7 +282,7 @@ void MainWindow::on_actionImportWad_triggered()
quint16 cnt = t.Count();
for( quint16 i = 0; i < cnt; i++ )
{
- job.data << wad.Content( i );
+ job.data << wad.Content( i );
}
job.decrypt = true;
@@ -295,7 +295,7 @@ void MainWindow::on_actionNew_nand_from_keys_triggered()
{
QString path = NewNandBin::GetNewNandPath( this );
if( path.isEmpty() )
- return;
+ return;
InitNand( path );
ui->lineEdit_nandPath->setText( path );
}
@@ -304,8 +304,8 @@ void MainWindow::on_pushButton_initNand_clicked()
{
if( ui->lineEdit_nandPath->text().isEmpty() )
{
- ShowMessage( "Please enter a path for nand.bin<\b>" );
- return;
+ ShowMessage( "Please enter a path for nand.bin<\b>" );
+ return;
}
InitNand( ui->lineEdit_nandPath->text() );
}
@@ -316,45 +316,45 @@ bool MainWindow::InitNand( const QString &path )
sharedDirty = false;
nandDirty = false;
if( !nand.SetPath( path ) || !nand.InitNand() )
- return false;
+ return false;
if( !UpdateTree() )
- return false;
+ 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( "Error creating new uid.sys" );
- return false;
- }
- uidDirty = true;
+ uid.CreateNew( true );
+ if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
+ {
+ ShowMessage( "Error creating new uid.sys" );
+ return false;
+ }
+ uidDirty = true;
}
else
{
- QByteArray ba = nand.GetData( "/sys/uid.sys" );
- uid = UIDmap( ba );
+ 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( "Error creating new content.map" );
- return false;
- }
+ if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
+ {
+ sharedDirty = true;
+ ShowMessage( "Error creating new content.map" );
+ 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( "Something about the shared map isnt right, but im using it anyways" );
+ 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( "Something about the shared map isnt right, but im using it anyways" );
}
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
@@ -372,15 +372,15 @@ bool MainWindow::FlushNand()
bool r1 = true;
bool r2 = true;
if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) )
- r1 = false;
+ r1 = false;
else
- uidDirty = false;
+ uidDirty = false;
if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) )
- r2 = false;
+ r2 = false;
else
- sharedDirty = false;
+ sharedDirty = false;
return ( nand.WriteMetaData() && r1 && r2 );
}
@@ -390,11 +390,11 @@ QTreeWidgetItem *MainWindow::FindItem( const QString &s, QTreeWidgetItem *parent
int cnt = parent->childCount();
for( int i = 0; i child( i );
- if( r->text( 0 ) == s )
- {
- return r;
- }
+ QTreeWidgetItem *r = parent->child( i );
+ if( r->text( 0 ) == s )
+ {
+ return r;
+ }
}
return NULL;
}
@@ -404,20 +404,20 @@ QTreeWidgetItem *MainWindow::ItemFromPath( const QString &path )
QTreeWidgetItem *item = root;
if( !path.startsWith( "/" ) || path.contains( "//" ))
{
- return NULL;
+ 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;
+ 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;
}
@@ -427,10 +427,10 @@ 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;
+ ret.prepend( "/" + item->text( 0 ) );
+ item = item->parent();
+ if( item->text( 0 ) == "/" )// dont add the root
+ break;
}
return ret;
}
@@ -439,12 +439,12 @@ 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;
+ 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;
+ ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" );
+ return false;
}
root = r->takeChild( 0 );
delete r;
@@ -454,14 +454,14 @@ bool MainWindow::UpdateTree()
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;
+ // 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;
+ 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();
@@ -472,13 +472,13 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray
//qDebug() << "MainWindow::InstallSharedContent";
QByteArray h;
if( hash.isEmpty() )
- h = GetSha1( stuff );
+ h = GetSha1( stuff );
else
- h = hash;
+ h = hash;
QString cid = shared.GetAppFromHash( hash );
if( !cid.isEmpty() ) //this one is already installed
- return true;
+ return true;
//qDebug() << "will create new";
//get next available cid in the shared map
@@ -490,7 +490,7 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray
//create the file
quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
if( !r )
- return false;
+ return false;
//write the data to the file
return nand.SetData( r, stuff );
@@ -509,9 +509,9 @@ bool MainWindow::InstallNUSItem( NusJob job )
QTreeWidgetItem *content;
if( !job.tid || !job.data.size() > 2 )
{
- qWarning() << "bad sizes";
- ShowMessage( "Error installing title " + title + " to nand" );
- return false;
+ qWarning() << "bad sizes";
+ ShowMessage( "Error installing title " + title + " to nand" );
+ return false;
}
QString tid = QString( "%1" ).arg( job.tid, 16, 16, QChar( '0' ) );
QString upper = tid.left( 8 );
@@ -521,19 +521,19 @@ bool MainWindow::InstallNUSItem( NusJob job )
Ticket ticket( job.data.takeFirst() );
if( t.Tid() != job.tid || ticket.Tid() != job.tid )
{
- qWarning() << "bad tid";
- goto error;
+ qWarning() << "bad tid";
+ goto error;
}
cnt = t.Count();
if( job.data.size() != cnt )
{
- qWarning() << "content count";
- goto error;
+ qWarning() << "content count";
+ goto error;
}
//qDebug() << "uidDirty" << uidDirty;
if( !uidDirty )
{
- uidDirty = !uid.GetUid( job.tid, false );
+ uidDirty = !uid.GetUid( job.tid, false );
}
//qDebug() << "uidDirty" << uidDirty;
_uid = uid.GetUid( job.tid );
@@ -541,8 +541,8 @@ bool MainWindow::InstallNUSItem( NusJob job )
_gid = t.Gid();
if( !_uid )
{
- qWarning() << "no uid";
- goto error;
+ qWarning() << "no uid";
+ goto error;
}
//create all the folders
@@ -566,15 +566,15 @@ bool MainWindow::InstallNUSItem( NusJob job )
cnt = content->childCount();
for ( quint16 i = 0; i < cnt; i++ )
{
- if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) )
+ if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) )
{ qWarning() << "error deleting old title"; goto error; }
- deleted = true;
+ deleted = true;
}
if( deleted )
{
- //nand.WriteMetaData();
- UpdateTree();
- ShowMessage( tr( "Deleted old TMD and private contents for
%1" ).arg( title ) );
+ //nand.WriteMetaData();
+ UpdateTree();
+ ShowMessage( tr( "Deleted old TMD and private contents for
%1" ).arg( title ) );
}
cnt = t.Count();
@@ -597,64 +597,64 @@ bool MainWindow::InstallNUSItem( NusJob job )
//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 ) );
- }
+ //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;
- }
+ //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;
- }
+ //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" );
@@ -662,7 +662,7 @@ bool MainWindow::InstallNUSItem( NusJob job )
//nand.Delete( "/title/" + upper );
//UpdateTree();
return true;
-error:
+ error:
ShowMessage( "Error installing title " + title + " to nand" );
return false;
}
@@ -671,9 +671,9 @@ error:
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."
- "
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"
- "
YOU HAVE BEEN WARNED"
- "
giantpune" );
+ "
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"
+ "
YOU HAVE BEEN WARNED"
+ "
giantpune" );
QMessageBox::critical( this, tr( "About" ), txt );
}
diff --git a/ohneschwanzenegger/newnandbin.cpp b/ohneschwanzenegger/newnandbin.cpp
index da295d1..aefb633 100644
--- a/ohneschwanzenegger/newnandbin.cpp
+++ b/ohneschwanzenegger/newnandbin.cpp
@@ -8,9 +8,9 @@ NewNandBin::NewNandBin( QWidget *parent, QList badBlocks ) : QDialog(pa
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 );
+ QString txt = QString( "%1" ).arg( block );
+ if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() )
+ ui->listWidget_badBlocks->addItem( txt );
}
}
@@ -23,7 +23,7 @@ void NewNandBin::on_pushButton_keys_clicked()
{
QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ), dir );
if( f.isEmpty() )
- return;
+ return;
ui->lineEdit_keys->setText( f );
dir = QFileInfo( f ).canonicalPath();
}
@@ -32,7 +32,7 @@ void NewNandBin::on_pushButton_boot_clicked()
{
QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ), dir );
if( f.isEmpty() )
- return;
+ return;
ui->lineEdit_boot->setText( f );
dir = QFileInfo( f ).canonicalPath();
}
@@ -41,7 +41,7 @@ void NewNandBin::on_pushButton_dest_clicked()
{
QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ), dir );
if( f.isEmpty() )
- return;
+ return;
ui->lineEdit_dest->setText( f );
dir = QFileInfo( f ).canonicalPath();
}
@@ -52,10 +52,10 @@ QList NewNandBin::BadBlocks()
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;
+ bool ok = false;
+ quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok );
+ if( ok )
+ ret << num;
}
return ret;
}
@@ -65,7 +65,7 @@ void NewNandBin::on_pushButton_bb_add_clicked()
quint16 val = ui->spinBox->value();
if( !BadBlocks().contains( val ) )
{
- ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) );
+ ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) );
}
}
@@ -74,8 +74,8 @@ void NewNandBin::on_pushButton_bb_rm_clicked()
QList items = ui->listWidget_badBlocks->selectedItems();
foreach( QListWidgetItem *item, items )
{
- ui->listWidget_badBlocks->removeItemWidget( item );
- delete item;
+ ui->listWidget_badBlocks->removeItemWidget( item );
+ delete item;
}
}
@@ -84,35 +84,48 @@ 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;
+ 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;
+ 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() << "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() )
+ || !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;
+ qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating directories in the new nand";
+ return;
}
+ //add cert.sys
+ quint16 handle = nand.CreateEntry( "/sys/cert.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_READ );
+ if( !handle || !nand.SetData( "/sys/cert.sys", QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) ) )
+ {
+ qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating cert in the new nand";
+ return;
+ }
+ //commit changes to metadata
+ if( !nand.WriteMetaData() )
+ {
+ qWarning() << "NewNandBin::on_buttonBox_accepted -> error writing metadata";
+ return;
+ }
ret = ui->lineEdit_dest->text();
}
@@ -121,7 +134,7 @@ QString NewNandBin::GetNewNandPath( QWidget *parent, QList badBlocks )
{
NewNandBin d( parent, badBlocks );
if( !d.exec() )
- return QString();
+ return QString();
return d.ret;
}
@@ -130,13 +143,13 @@ void NewNandBin::on_pushButton_badBlockFile_clicked()
{
QString f = QFileDialog::getOpenFileName( this, tr( "Select File with Bad Block List" ), dir );
if( f.isEmpty() )
- return;
+ return;
dir = QFileInfo( f ).canonicalPath();
QString str = QString( ReadFile( f ) );
if( str.isEmpty() )
{
- qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file";
- return;
+ qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file";
+ return;
}
ui->listWidget_badBlocks->clear();
@@ -144,17 +157,17 @@ void NewNandBin::on_pushButton_badBlockFile_clicked()
QStringList lines = str.split( "\n", QString::SkipEmptyParts );
foreach( QString line, lines )
{
- if( line.size() > 5 )
- continue;
- bool ok = false;
+ if( line.size() > 5 )
+ continue;
+ bool ok = false;
- if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list
- continue;
+ if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list
+ continue;
- quint16 bb = line.toInt( &ok );
- if( !ok || bb < 8 || bb > 4079 )
- continue;
+ quint16 bb = line.toInt( &ok );
+ if( !ok || bb < 8 || bb > 4079 )
+ continue;
- ui->listWidget_badBlocks->addItem( line );
+ ui->listWidget_badBlocks->addItem( line );
}
}
diff --git a/saveToy/readmii.txt b/saveToy/readmii.txt
index 0d22e39..b985f87 100644
--- a/saveToy/readmii.txt
+++ b/saveToy/readmii.txt
@@ -1,4 +1,11 @@
-this is a tool to list saves in an extracted nand dump
+this is a tool to list/extract/delete saves to/from an extracted nand dump. saves are extracted, packed into a data.bin, zipped up with a txt file
+ that says a bit about the save, and then stored in a folder. you must designate a folder and provide the necessary keys before extracting saves
+will work. i chose to go with data.bin as it is a way to store the entire save in 1 file and also allow the save to be installed using the
+system menu. and i went with the zip format 1) to save space, and 2) to keep a save and the description all in 1 compact file.
+
+saves are extracted to "///#.zip". the # is chosen by the lowest available number starting with 1.
+there is no need for the saves to be in numerical order, if you have 10 zips for the same game and you decide to delete "3.zip", it will cause
+no issues, and next time you extract a save for this game, it will use the filename "3.zip".
TODO:
-add some sort of extract/delete/install functionality
+installing saves back to sneek nand still isnt done