diff --git a/WiiQt/nanddump.cpp b/WiiQt/nanddump.cpp index f52e85d..c0d27df 100644 --- a/WiiQt/nanddump.cpp +++ b/WiiQt/nanddump.cpp @@ -418,6 +418,80 @@ bool NandDump::InstallNusItem( NusJob job ) return true; } +bool NandDump::InstallWad( Wad wad ) +{ + if( !wad.Tid() || wad.content_count() < 3 ) + { + qWarning() << "NandDump::InstallNusItem -> invalid item"; + return false; + } + if( !uidDirty ) + { + uidDirty = uidMap.GetUid( wad.Tid(), false ) == 0;//only flag the uid as dirty if it has to be, this way it is only flushed if needed + } + uidMap.GetUid( wad.Tid() ); + QString p = QString( "%1" ).arg( wad.Tid(), 16, 16, QChar( '0' ) ); + p.insert( 8 ,"/" ); + p.prepend( "/title/" ); + QString path = basePath + p + "/content"; + if( !QFileInfo( path ).exists() && !QDir().mkpath( path ) ) + return false; + + path = basePath + p + "/data"; + if( !QFileInfo( path ).exists() && !QDir().mkpath( path ) ) + return false; + + QByteArray ba = wad.getTmd(); + if( !InstallTmd( ba, wad.Tid() ) ) + return false; + + Tmd t( ba ); + + ba = wad.getTik(); + Ticket ti( ba ); + if( !InstallTicket( ba, wad.Tid() ) ) + { + AbortInstalling( wad.Tid() ); + return false; + } + + quint32 cnt = qFromBigEndian( t.payload()->num_contents ); + if( cnt != wad.content_count() ) + { + AbortInstalling( wad.Tid() ); + return false; + } + + for( quint32 i = 0; i < cnt; i++ ) + { + QByteArray decData = wad.Content(i); + + if( t.Type( i ) == 0x8001 ) + { + if( !InstallSharedContent( decData, t.Hash( i ) ) ) + { + AbortInstalling( wad.Tid() ); + return false; + } + } + else if( t.Type( i ) == 1 ) + { + if( !InstallPrivateContent( decData, wad.Tid(), t.Cid( i ) ) ) + { + AbortInstalling( wad.Tid() ); + return false; + } + } + else//unknown content type + { + qWarning() << "NandDump::InstallWad -> unknown content type"; + AbortInstalling( wad.Tid() ); + return false; + } + } + return true; +} + QMap< quint64, quint16 > NandDump::GetInstalledTitles() { QMap< quint64, quint16 >ret; diff --git a/WiiQt/nanddump.h b/WiiQt/nanddump.h index b8de5c7..efe5fd3 100644 --- a/WiiQt/nanddump.h +++ b/WiiQt/nanddump.h @@ -5,6 +5,7 @@ #include "includes.h" #include "sharedcontentmap.h" #include "uidmap.h" +#include "wad.h" struct SaveGame//struct to hold save data { @@ -54,6 +55,10 @@ public: //returns false if something went wrong bool InstallNusItem( NusJob job ); + //installs a title to the nand dump from a wad + //returns false if something went wrong + bool InstallWad( Wad wad ); + //tries to delete a title from the nand dump //deleteData gives the option to just delete the title and leave behind its data bool DeleteTitle( quint64 tid, bool deleteData = false ); diff --git a/WiiQt/nusdownloader.cpp b/WiiQt/nusdownloader.cpp index 5e08010..6a406e2 100644 --- a/WiiQt/nusdownloader.cpp +++ b/WiiQt/nusdownloader.cpp @@ -618,7 +618,7 @@ QMap< quint64, quint16 > NusDownloader::List31j() //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( 0x100024841464a, 0x7 ); // forcast v7 HAFJ + titles.insert( 0x100024841464aull, 0x7 );// forcast v7 HAFJ titles.insert( 0x100000101ull, 5 );//miosv5 titles.insert( 0x1000848414C4aull, 0x2 );//regsel //region select isnt in the paper mario update, but putting it here just to be safe titles.insert( 0x1000248414341ull, 0x2 );//nigaoeNRv2 - MII diff --git a/WiiQt/wad.cpp b/WiiQt/wad.cpp index fa53750..ec1d01c 100644 --- a/WiiQt/wad.cpp +++ b/WiiQt/wad.cpp @@ -6,34 +6,42 @@ static QByteArray globalCert; Wad::Wad( const QByteArray stuff ) { - ok = false; - if( stuff.size() < 0x80 )//less than this and there is definitely nothing there - { - Err( "Size is < 0x80" ); - return; - } + ok = false; + if( stuff.size() < 0x80 )//less than this and there is definitely nothing there + { + Err( "Size is < 0x80" ); + return; + } - QByteArray copy = stuff; - QBuffer b( © ); - b.open( QIODevice::ReadOnly ); + QByteArray copy = stuff; + QBuffer b( © ); + b.open( QIODevice::ReadOnly ); - quint32 tmp; - b.read( (char*)&tmp, 4 ); - if( qFromBigEndian( tmp ) != 0x20 ) - { - b.close(); - Err( "Bad header size" ); - return; - } - b.read( (char*)&tmp, 4 ); - tmp = qFromBigEndian( tmp ); - if( tmp != 0x49730000 && tmp != 0x69620000 && tmp != 0x426b0000 ) - { - b.close(); - hexdump( stuff, 0, 0x40 ); - Err( "Bad file magic word" ); - return; - } + quint32 tmp; + if(b.read( (char*)&tmp, 4 ) != 4) + { + b.close(); + Err( "Can't read header size" ); + return; + } + if( qFromBigEndian( tmp ) != 0x20 ) + { + b.close(); + hexdump(stuff, 0, 0x10); + Err( "Bad header size" ); + return; + } + b.read( (char*)&tmp, 4 ); + tmp = qFromBigEndian( tmp ); + if( tmp != 0x49730000 && + tmp != 0x69620000 && + tmp != 0x426b0000 ) + { + b.close(); + hexdump( stuff, 0, 0x40 ); + Err( "Bad file magic word" ); + return; + } quint32 certSize; quint32 tikSize; @@ -184,6 +192,16 @@ void Wad::SetGlobalCert( const QByteArray &stuff ) globalCert = stuff; } +const QByteArray Wad::getTmd() +{ + return tmdData; +} + +const QByteArray Wad::getTik() +{ + return tikData; +} + const QByteArray Wad::Content( quint16 i ) { if( tmdData.isEmpty() || tikData.isEmpty() ) @@ -213,6 +231,11 @@ const QByteArray Wad::Content( quint16 i ) return decData; } +quint32 Wad::content_count() +{ + return partsEnc.size(); +} + void Wad::Err( QString str ) { ok = false; diff --git a/WiiQt/wad.h b/WiiQt/wad.h index 908455a..119c4d4 100644 --- a/WiiQt/wad.h +++ b/WiiQt/wad.h @@ -50,10 +50,19 @@ public: //get all the parts of this wad put together in a wad ready for writing to disc or whatever const QByteArray Data( quint32 magicWord = 0x49730000, const QByteArray footer = QByteArray() ); + + //get the tmd for the wad + const QByteArray getTmd(); + + //get the tik for the wad + const QByteArray getTik(); //get the decrypted data from a content const QByteArray Content( quint16 i ); + //get the number of contents + quint32 content_count(); + //get the last error encountered while trying to do something const QString LastError(){ return errStr; } diff --git a/nand_dump/mainwindow.cpp b/nand_dump/mainwindow.cpp index 0730f1b..bbaed57 100644 --- a/nand_dump/mainwindow.cpp +++ b/nand_dump/mainwindow.cpp @@ -313,6 +313,52 @@ void MainWindow::on_actionFlush_triggered() nand.Flush(); } +//nand-dump -> ImportWad +void MainWindow::on_actionImportWad_triggered() +{ + if( nand.GetPath() != ui->lineEdit_nandPath->text() && + !nand.SetPath( ui->lineEdit_nandPath->text() ) ) + { + ShowMessage( tr( "Error setting the basepath of the nand to %1" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); + return; + } + QString fn = QFileDialog::getSaveFileName(this, + tr("Wad files(*.wad)"), + QCoreApplication::applicationDirPath(), + tr("WadFiles (*.wad)")); + if(fn == "") return; + + QFile f(fn); + if(!f.open( QIODevice::ReadOnly)) { + ShowMessage( tr( "Error opening %1" ).arg( fn ) ); + return; + } + + qint64 len = f.size(); + char* buffer = new char[len]; + qint64 read = f.read(buffer, len); + f.close(); + hexdump(buffer, 0x40); + if(read != len) { + ShowMessage( tr( "Error reading %1" ).arg( fn ) ); + free(buffer); + return; + } + QByteArray data(buffer, len); + free(buffer); + Wad wad(data); + if( !wad.IsOk() ) { + ShowMessage( tr( "Wad data not ok" ) );; + return; + } + + bool ok = nand.InstallWad( wad ); + if( ok ) + ShowMessage( tr( "Installed %1 title to nand" ).arg( wad.WadName() ) ); + else + ShowMessage( tr( "Error %1 title to nand" ).arg( wad.WadName() ) ); +} + //save a NUS job to a folder void MainWindow::SaveJobToFolder( NusJob job ) { diff --git a/nand_dump/mainwindow.h b/nand_dump/mainwindow.h index 48e5b00..2208d7f 100644 --- a/nand_dump/mainwindow.h +++ b/nand_dump/mainwindow.h @@ -41,6 +41,7 @@ public slots: private slots: void on_actionFlush_triggered(); void on_actionSetting_txt_triggered(); + void on_actionImportWad_triggered(); void on_pushButton_wad_clicked(); void on_pushButton_decFolder_clicked(); void on_pushButton_nandPath_clicked(); diff --git a/nand_dump/mainwindow.ui b/nand_dump/mainwindow.ui index 8fbe134..edfb471 100644 --- a/nand_dump/mainwindow.ui +++ b/nand_dump/mainwindow.ui @@ -218,6 +218,7 @@ + @@ -240,6 +241,11 @@ Flush + + + Import Wad + +