From 4ad7db8134633a1f35fa7e8320dbef325af4832b Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 23 Aug 2016 13:09:23 -0400 Subject: [PATCH] rename nand_dump --- build.sh | 12 + nandDump/icon.png | Bin 0 -> 7905 bytes nandDump/main.cpp | 13 + nandDump/mainwindow.cpp | 571 ++++++++++++++++++++++++++++++++++++++++ nandDump/mainwindow.h | 59 +++++ nandDump/mainwindow.ui | 262 ++++++++++++++++++ nandDump/nand.pro | 41 +++ nandDump/rc.qrc | 5 + nandDump/readmii.txt | 5 + 9 files changed, 968 insertions(+) create mode 100755 build.sh create mode 100755 nandDump/icon.png create mode 100644 nandDump/main.cpp create mode 100644 nandDump/mainwindow.cpp create mode 100644 nandDump/mainwindow.h create mode 100644 nandDump/mainwindow.ui create mode 100644 nandDump/nand.pro create mode 100644 nandDump/rc.qrc create mode 100644 nandDump/readmii.txt diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b5a3399 --- /dev/null +++ b/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +mkdir -p bin + +for app in nandBinCheck nandDump nandExtract ohneschwanzenegger +do + cd $app + qmake + make -j4 + cp $app ../bin + cd .. +done diff --git a/nandDump/icon.png b/nandDump/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..9103c505a90599dee547c6e7da12e4a457a219e4 GIT binary patch literal 7905 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 literal 0 HcmV?d00001 diff --git a/nandDump/main.cpp b/nandDump/main.cpp new file mode 100644 index 0000000..1b39053 --- /dev/null +++ b/nandDump/main.cpp @@ -0,0 +1,13 @@ +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE( rc ); + QApplication a(argc, argv); + QApplication::setWindowIcon( QIcon( ":/icon.png" ) ); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/nandDump/mainwindow.cpp b/nandDump/mainwindow.cpp new file mode 100644 index 0000000..a481b81 --- /dev/null +++ b/nandDump/mainwindow.cpp @@ -0,0 +1,571 @@ +#include "mainwindow.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 ) +{ + ui->setupUi(this); + ui->mainToolBar->setVisible( false );//hide toolbar for now + + //resize buttons to be same size + QFontMetrics fm( fontMetrics() ); + int max = fm.width( ui->pushButton_CachePathBrowse->text() ); + max = MAX( max, fm.width( ui->pushButton_decFolder->text() ) ); + max = MAX( max, fm.width( ui->pushButton_GetTitle->text() ) ); + max = MAX( max, fm.width( ui->pushButton_nandPath->text() ) ); + max = MAX( max, fm.width( ui->pushButton_wad->text() ) ); + + max += 15; + ui->pushButton_CachePathBrowse->setMinimumWidth( max ); + ui->pushButton_decFolder->setMinimumWidth( max ); + ui->pushButton_GetTitle->setMinimumWidth( max ); + ui->pushButton_nandPath->setMinimumWidth( max ); + ui->pushButton_wad->setMinimumWidth( max ); + + 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 &, const NusJob & ) ), this, SLOT( GetError( const QString &, const NusJob & ) ) ); + connect( &nus, SIGNAL( SendDone() ), this, SLOT( NusIsDone() ) ); + connect( &nus, SIGNAL( SendData( const NusJob & ) ), this, SLOT( ReceiveTitleFromNus( const NusJob & ) ) ); + + LoadSettings(); +} + +MainWindow::~MainWindow() +{ + SaveSettings(); + delete ui; +} + +void MainWindow::SaveSettings() +{ + QSettings s( QSettings::IniFormat, QSettings::UserScope, "WiiQt", "examples", this ); + + //settings specific to this program + s.beginGroup( "nusDownloader" ); + //window geometry + s.setValue( "size", size() ); + s.setValue( "pos", pos() ); + + //which radio button is selected + quint8 val = 0; + if( ui->radioButton_folder->isChecked() ) + val = 1; + else if( ui->radioButton_wad->isChecked() ) + val = 2; + s.setValue( "radio", val ); + + s.setValue( "folder", ui->lineEdit_extractPath->text() ); + s.setValue( "nuswads", ui->lineEdit_wad->text() ); + + s.endGroup(); + + //settings shared in multiple programs + //paths + s.beginGroup( "paths" ); + s.setValue( "nusCache", ui->lineEdit_cachePath->text() ); + s.setValue( "sneek", ui->lineEdit_nandPath->text() ); + s.endGroup(); + +} +#ifdef Q_WS_WIN +#define PATH_PREFIX QString("../..") +#else +#define PATH_PREFIX QString("..") +#endif + +void MainWindow::LoadSettings() +{ + QSettings s( QSettings::IniFormat, QSettings::UserScope, "WiiQt", "examples", this ); + + //settings specific to this program + s.beginGroup( "nusDownloader" ); + resize( s.value("size", QSize( 585, 457 ) ).toSize() ); + move( s.value("pos", QPoint( 2, 72 ) ).toPoint() ); + + quint8 radio = s.value( "radio", 0 ).toInt(); + if( radio == 1 ) + ui->radioButton_folder->setChecked( true ); + else if( radio == 2 ) + ui->radioButton_wad->setChecked( true ); + + ui->lineEdit_extractPath->setText( s.value( "folder", PATH_PREFIX + "/downloaded" ).toString() ); + ui->lineEdit_wad->setText( s.value( "nuswads", PATH_PREFIX + "/wads" ).toString() ); + + s.endGroup(); + + //settings shared in multiple programs + s.beginGroup( "paths" ); + + QString cachePath = s.value( "nusCache", PATH_PREFIX + "/NUS_cache" ).toString(); + QString nandPath = s.value( "sneek" ).toString(); + ui->lineEdit_cachePath->setText( cachePath ); + ui->lineEdit_nandPath->setText( nandPath ); + + if( !nandPath.isEmpty() ) + nand.SetPath( QFileInfo( nandPath ).absoluteFilePath() ); + if( !cachePath.isEmpty() ) + nus.SetCachePath( QFileInfo( cachePath ).absoluteFilePath() ); + s.endGroup(); + +} + +//some slots to respond to the NUS downloader +void MainWindow::GetError( const QString &message, const 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( "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 ); + + + ui->plainTextEdit_log->appendHtml( str ); + ui->plainTextEdit_log->appendHtml( j ); +} + +void MainWindow::ShowMessage( const QString& mes ) +{ + QString str = mes + "
"; + ui->plainTextEdit_log->appendHtml( str ); +} + +void MainWindow::NusIsDone() +{ + QString str = tr( "NUS object is done working
" ); + ui->plainTextEdit_log->appendHtml( str ); + ui->statusBar->showMessage( tr( "Done" ), 5000 ); + if( ui->radioButton_folder->isChecked() ) + { + ui->lineEdit_extractPath->setEnabled( true ); + ui->pushButton_decFolder->setEnabled( true ); + } + else if( ui->radioButton_nand->isChecked() ) + { + //check if IOS35 is present in nand dump - needed for sneek + QByteArray tmdBA = nand.GetFile( "/title/00000001/00000023/content/title.tmd" ); + if( tmdBA.isEmpty() ) + { + ui->plainTextEdit_log->appendHtml( tr( "IOS35 not found on nand. Getting it now...") ); + nus.Get( 0x100000023ull, true ); + return; + } + ui->lineEdit_nandPath->setEnabled( true ); + ui->pushButton_nandPath->setEnabled( true ); + + //write the uid.sys and content.map to disc + ShowMessage( tr( "Flushing nand..." ) ); + nand.Flush(); + + //make sure there is a setting.txt + QByteArray set = nand.GetSettingTxt(); + if( set.isEmpty() ) + { + 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; + set = SettingTxtDialog::Edit( this, QByteArray(), reg ); + if( !set.isEmpty() ) + nand.SetSettingTxt( set ); + } + /*QMap< quint64, quint16 > t = nand.GetInstalledTitles(); + QMap< quint64, quint16 >::iterator i = t.begin(); + while( i != t.end() ) + { + QString title = QString( "%1v%2" ).arg( i.key(), 16, 16, QChar( '0' ) ).arg( i.value() ); + qDebug() << "title:" << title; + i++; + }*/ + } + else if( ui->radioButton_wad->isChecked() ) + { + ui->lineEdit_wad->setEnabled( true ); + ui->pushButton_wad->setEnabled( true ); + } + + ui->radioButton_folder->setEnabled( true ); + ui->radioButton_nand->setEnabled( true ); + ui->radioButton_wad->setEnabled( true ); +} + +void MainWindow::ReceiveTitleFromNus( const 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( ui->radioButton_folder->isChecked() )//copy its decrypted contents to a folder + { + SaveJobToFolder( job ); + } + else if( ui->radioButton_nand->isChecked() )//install this title to a decrypted nand dump for sneek/dolphin + { + bool ok = nand.InstallNusItem( job ); + if( ok ) + ShowMessage( tr( "Installed %1 title to nand" ).arg( title ) ); + else + ShowMessage( tr( "Error installing %1 title to nand" ).arg( title ) ); + } + else if( ui->radioButton_wad->isChecked() ) + { + SaveJobToWad( job ); + } +} + +//clicked the button to get a title +void MainWindow::on_pushButton_GetTitle_clicked() +{ + 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( "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; + if( ui->radioButton_folder->isChecked() ) + { + if( ui->lineEdit_extractPath->text().isEmpty() ) + { + ShowMessage( tr( "No path given to save downloads in." ) ); + return; + } + ui->lineEdit_extractPath->setEnabled( false ); + ui->pushButton_decFolder->setEnabled( false ); + } + else if( ui->radioButton_nand->isChecked() ) + { + 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; + } + if( ui->lineEdit_nandPath->text().isEmpty() ) + { + ShowMessage( tr( "No path given for nand dump base." ) ); + return; + } + ui->lineEdit_nandPath->setEnabled( false ); + ui->pushButton_nandPath->setEnabled( false ); + } + else if( ui->radioButton_wad->isChecked() ) + { + if( ui->lineEdit_wad->text().isEmpty() ) + { + ShowMessage( tr( "No path given to save wads in." ) ); + return; + } + decrypt = false; + ui->lineEdit_wad->setEnabled( false ); + ui->pushButton_wad->setEnabled( false ); + + } + + ui->radioButton_folder->setEnabled( false ); + ui->radioButton_nand->setEnabled( false ); + ui->radioButton_wad->setEnabled( false ); + //dont set these to 0 in case the button is pressed while something else is already being downloaded + //ui->progressBar_dl->setValue( 0 ); + //ui->progressBar_title->setValue( 0 ); + //ui->progressBar_whole->setValue( 0 ); + nus.SetCachePath( QFileInfo( ui->lineEdit_cachePath->text() ).absoluteFilePath() ); + + 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; + } + } + else + { + nus.Get( tid, decrypt, ver ); + } +} + +//ratio buttons toggled +void MainWindow::on_radioButton_nand_toggled( bool checked ) +{ + ui->lineEdit_nandPath->setEnabled( checked ); + ui->pushButton_nandPath->setEnabled( checked ); +} + +void MainWindow::on_radioButton_folder_toggled( bool checked ) +{ + ui->lineEdit_extractPath->setEnabled( checked ); + ui->pushButton_decFolder->setEnabled( checked ); +} + +void MainWindow::on_radioButton_wad_toggled( bool checked ) +{ + ui->lineEdit_wad->setEnabled( checked ); + ui->pushButton_wad->setEnabled( checked ); +} + +//search for a path to use as the nand basepath +void MainWindow::on_pushButton_nandPath_clicked() +{ + QString path = ui->lineEdit_nandPath->text().isEmpty() ? "/media" : ui->lineEdit_nandPath->text(); + QString f = QFileDialog::getExistingDirectory( this, tr( "Select Nand Base Folder" ), path ); + if( f.isEmpty() ) + return; + + ui->lineEdit_nandPath->setText( f ); + nus.SetCachePath( ui->lineEdit_cachePath->text() ); +} + +void MainWindow::on_pushButton_decFolder_clicked() +{ + QString path = ui->lineEdit_extractPath->text().isEmpty() ? QDir::currentPath() : ui->lineEdit_extractPath->text(); + QString f = QFileDialog::getExistingDirectory( this, tr( "Select folder to save decrypted titles" ), path ); + if( f.isEmpty() ) + return; + + ui->lineEdit_extractPath->setText( f ); +} + +void MainWindow::on_pushButton_wad_clicked() +{ + QString path = ui->lineEdit_wad->text().isEmpty() ? QDir::currentPath() : ui->lineEdit_wad->text(); + QString f = QFileDialog::getExistingDirectory( this, tr( "Select folder to save wads to" ), path ); + if( f.isEmpty() ) + return; + + ui->lineEdit_wad->setText( f ); +} + +//nand-dump -> setting.txt +void MainWindow::on_actionSetting_txt_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; + } + QByteArray ba = nand.GetSettingTxt(); //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.SetSettingTxt( ba ); +} + +//nand-dump -> flush +void MainWindow::on_actionFlush_triggered() +{ + if( !nand.GetPath().isEmpty() ) + 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 path = ui->lineEdit_wad->text().isEmpty() ? + QCoreApplication::applicationDirPath() : ui->lineEdit_wad->text(); + QString fn = QFileDialog::getOpenFileName( this, + tr("Wad files(*.wad)"), + path, + tr("WadFiles (*.wad)")); + if(fn == "") return; + + QByteArray data = ReadFile( fn ); + if( data.isEmpty() ) + return; + + 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 ) +{ + QString title = QString( "%1v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version ); + QFileInfo fi( ui->lineEdit_extractPath->text() ); + if( fi.isFile() ) + { + ShowMessage( "" + ui->lineEdit_extractPath->text() + " is a file. I need a folder<\b>" ); + return; + } + if( !fi.exists() ) + { + ShowMessage( "" + fi.absoluteFilePath() + " is not a folder!\nTrying to create it...<\b>" ); + if( !QDir().mkpath( fi.absoluteFilePath() ) ) + { + ShowMessage( "Failed to make the directory!<\b>" ); + return; + } + } + QString newFName = title; + int i = 1; + while( QFileInfo( fi.absoluteFilePath() + "/" + newFName ).exists() )//find a folder that doesnt exist and try to create it + { + newFName = QString( "%1 (copy%2)" ).arg( title ).arg( i++ ); + } + if( !QDir().mkpath( fi.absoluteFilePath() + "/" + newFName ) ) + { + ShowMessage( "Can't create" + fi.absoluteFilePath() + "/" + newFName + " to save this title into!<\b>" ); + return; + } + //start writing all this stuff to the HDD + QDir d( fi.absoluteFilePath() + "/" + newFName ); + QByteArray tmdDat = job.data.takeFirst(); //remember the tmd and use it for getting the names of the .app files + if( !WriteFile( d.absoluteFilePath( "title.tmd" ), tmdDat ) ) + { + ShowMessage( "Error writing " + d.absoluteFilePath( "title.tmd" ) + "!<\b>" ); + return; + } + if( !WriteFile( d.absoluteFilePath( "cetk" ), job.data.takeFirst() ) ) + { + ShowMessage( "Error writing " + d.absoluteFilePath( "cetk" ) + "!<\b>" ); + return; + } + Tmd t( tmdDat ); + quint16 cnt = t.Count(); + if( job.data.size() != cnt ) + { + ShowMessage( "Error! Number of contents in the TMD dont match the number received from NUS!<\b>" ); + return; + } + for( quint16 i = 0; i < cnt; i++ )//write all the contents in the new folder. if the job is decrypted, append ".app" to the end of their names + { + QString appName = t.Cid( i ); + QByteArray stuff = job.data.takeFirst(); + if( job.decrypt ) + { + appName += ".app"; + //qDebug() << "resizing from" << hex << stuff.size() << "to" << (quint32)t.Size( i ); + //stuff.resize( t.Size( i ) ); + } + if( !WriteFile( d.absoluteFilePath( appName ), stuff ) ) + { + ShowMessage( "Error writing " + d.absoluteFilePath( appName ) + "!<\b>" ); + return; + } + } + ShowMessage( tr( "Wrote title to %1" ).arg( fi.absoluteFilePath() + "/" + newFName ) ); +} + +//save a completed job to wad +void MainWindow::SaveJobToWad( NusJob job ) +{ + QString title = QString( "%1v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version ); + Wad wad( job.data ); + if( !wad.IsOk() ) + { + ShowMessage( "Error making a wad from " + title + "<\b>" ); + return; + } + QFileInfo fi( ui->lineEdit_wad->text() ); + if( fi.isFile() ) + { + ShowMessage( "" + ui->lineEdit_wad->text() + " is a file. I need a folder<\b>" ); + return; + } + if( !fi.exists() ) + { + ShowMessage( "" + fi.absoluteFilePath() + " is not a folder!\nTrying to create it...<\b>" ); + if( !QDir().mkpath( ui->lineEdit_wad->text() ) ) + { + ShowMessage( "Failed to make the directory!<\b>" ); + return; + } + } + QByteArray w = wad.Data(); + if( w.isEmpty() ) + { + ShowMessage( "Error creating wad
" + wad.LastError() + "<\b>" ); + return; + } + + QString name = wad.WadName( fi.absoluteFilePath() ); + if( name.isEmpty() ) + { + name = QFileDialog::getSaveFileName( this, tr( "Filename for %1" ).arg( title ), fi.absoluteFilePath() ); + if( name.isEmpty() ) + { + ShowMessage( "No save name given, aborting<\b>" ); + return; + } + } + QFile file( fi.absoluteFilePath() + "/" + name ); + if( !file.open( QIODevice::WriteOnly ) ) + { + ShowMessage( "Cant open " + fi.absoluteFilePath() + "/" + name + " for writing<\b>" ); + return; + } + file.write( w ); + file.close(); + ShowMessage( "Saved " + title + " to " + fi.absoluteFilePath() + "/" + name ); + + +} + +void MainWindow::on_pushButton_CachePathBrowse_clicked() +{ + QString f = QFileDialog::getExistingDirectory( this, tr( "Select NUS Cache base folder" ) ); + if( f.isEmpty() ) + return; + + ui->lineEdit_cachePath->setText( f ); + nus.SetCachePath( ui->lineEdit_cachePath->text() ); +} diff --git a/nandDump/mainwindow.h b/nandDump/mainwindow.h new file mode 100644 index 0000000..70448cd --- /dev/null +++ b/nandDump/mainwindow.h @@ -0,0 +1,59 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "../WiiQt/includes.h" +#include "../WiiQt/nusdownloader.h" +#include "../WiiQt/nanddump.h" + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow( QWidget *parent = 0 ); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + + NusDownloader nus; + NandDump nand; + + void ShowMessage( const QString& mes ); + + //do something with a completed download + void SaveJobToFolder( NusJob job ); + void SaveJobToWad( NusJob job ); + + //settings + void SaveSettings(); + void LoadSettings(); + + + +public slots: + //slots for getting info from the NUS downloader + void GetError( const QString &message, const NusJob &job ); + void NusIsDone(); + void ReceiveTitleFromNus( const NusJob &job ); + + +private slots: + void on_pushButton_CachePathBrowse_clicked(); + 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(); + void on_radioButton_wad_toggled(bool checked); + void on_radioButton_folder_toggled(bool checked); + void on_radioButton_nand_toggled(bool checked); + void on_pushButton_GetTitle_clicked(); +}; + +#endif // MAINWINDOW_H diff --git a/nandDump/mainwindow.ui b/nandDump/mainwindow.ui new file mode 100644 index 0000000..197dab6 --- /dev/null +++ b/nandDump/mainwindow.ui @@ -0,0 +1,262 @@ + + + MainWindow + + + + 0 + 0 + 585 + 457 + + + + QtShitGetter + + + + + + + + + + + + 16 + + + + + + + v + + + + + + + + 107 + 16777215 + + + + + + + 5 + + + + + + + Get It! + + + + + + + + + + + + + + Local Cache + + + + + + + + + + + + + Download + + + + + + + 0 + + + + + + + Title + + + + + + + 0 + + + + + + + Total + + + + + + + 0 + + + + + + + + + + + Nand + + + true + + + true + + + + + + + + + + Search... + + + + + + + Folder + + + + + + + false + + + + + + + false + + + Search... + + + + + + + Wad + + + + + + + false + + + + + + + false + + + Search... + + + + + + + + + + + + + + + + 0 + 0 + 585 + 27 + + + + + Nand Dump + + + + + + + + + + + TopToolBarArea + + + false + + + + + + Setting.txt... + + + + + Flush + + + + + Import Wad + + + Ctrl+I + + + + + Import Folder + + + + + + + diff --git a/nandDump/nand.pro b/nandDump/nand.pro new file mode 100644 index 0000000..59001a4 --- /dev/null +++ b/nandDump/nand.pro @@ -0,0 +1,41 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-12-02T23:30:12 +# +#------------------------------------------------- + +QT += core gui network widgets + +TARGET = nandDump +TEMPLATE = app + + +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 + +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 + +FORMS += mainwindow.ui \ + ../WiiQt/settingtxtdialog.ui + +RESOURCES += \ + rc.qrc diff --git a/nandDump/rc.qrc b/nandDump/rc.qrc new file mode 100644 index 0000000..619648d --- /dev/null +++ b/nandDump/rc.qrc @@ -0,0 +1,5 @@ + + + icon.png + + diff --git a/nandDump/readmii.txt b/nandDump/readmii.txt new file mode 100644 index 0000000..d68b99b --- /dev/null +++ b/nandDump/readmii.txt @@ -0,0 +1,5 @@ +this program downloads files from NUS. currently it supports installing them to an extracted nand dump for use in sneek/dolphin. +downloaded files can be cached to a local file so next time you try to download that title, you wont need to get it from NUS. + +TODO... +saving content to a seperate folder and packing wads is only partially done