mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
finish all the features
This commit is contained in:
159
src/DSi_NAND.cpp
159
src/DSi_NAND.cpp
@ -509,22 +509,25 @@ void debug_listfiles(const char* path)
|
|||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpFile(const char* path, const char* out)
|
bool ImportFile(const char* path, const char* in)
|
||||||
{
|
{
|
||||||
FIL file;
|
FIL file;
|
||||||
FILE* fout;
|
FILE* fin;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
|
fin = fopen(in, "rb");
|
||||||
if (res != FR_OK) return;
|
if (!fin)
|
||||||
|
return false;
|
||||||
|
|
||||||
u32 len = f_size(&file);
|
fseek(fin, 0, SEEK_END);
|
||||||
|
u32 len = (u32)ftell(fin);
|
||||||
|
fseek(fin, 0, SEEK_SET);
|
||||||
|
|
||||||
fout = fopen(out, "wb");
|
res = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
if (!fout)
|
if (res != FR_OK)
|
||||||
{
|
{
|
||||||
f_close(&file);
|
fclose(fin);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 buf[0x200];
|
u8 buf[0x200];
|
||||||
@ -536,13 +539,54 @@ void DumpFile(const char* path, const char* out)
|
|||||||
else
|
else
|
||||||
blocklen = 0x200;
|
blocklen = 0x200;
|
||||||
|
|
||||||
u32 burp;
|
u32 nwrite;
|
||||||
f_read(&file, buf, blocklen, &burp);
|
fread(buf, blocklen, 1, fin);
|
||||||
|
f_write(&file, buf, blocklen, &nwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fin);
|
||||||
|
f_close(&file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExportFile(const char* path, const char* out)
|
||||||
|
{
|
||||||
|
FIL file;
|
||||||
|
FILE* fout;
|
||||||
|
FRESULT res;
|
||||||
|
|
||||||
|
res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
|
||||||
|
if (res != FR_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u32 len = f_size(&file);
|
||||||
|
|
||||||
|
fout = fopen(out, "wb");
|
||||||
|
if (!fout)
|
||||||
|
{
|
||||||
|
f_close(&file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 buf[0x200];
|
||||||
|
for (u32 i = 0; i < len; i += 0x200)
|
||||||
|
{
|
||||||
|
u32 blocklen;
|
||||||
|
if ((i + 0x200) > len)
|
||||||
|
blocklen = len - i;
|
||||||
|
else
|
||||||
|
blocklen = 0x200;
|
||||||
|
|
||||||
|
u32 nread;
|
||||||
|
f_read(&file, buf, blocklen, &nread);
|
||||||
fwrite(buf, blocklen, 1, fout);
|
fwrite(buf, blocklen, 1, fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveFile(const char* path)
|
void RemoveFile(const char* path)
|
||||||
@ -692,6 +736,9 @@ bool TitleExists(u32 category, u32 titleid)
|
|||||||
void GetTitleInfo(u32 category, u32 titleid, u32& version, u8* header, u8* banner)
|
void GetTitleInfo(u32 category, u32 titleid, u32& version, u8* header, u8* banner)
|
||||||
{
|
{
|
||||||
version = GetTitleVersion(category, titleid);
|
version = GetTitleVersion(category, titleid);
|
||||||
|
if (version == 0xFFFFFFFF)
|
||||||
|
return;
|
||||||
|
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
char path[256];
|
char path[256];
|
||||||
@ -704,6 +751,8 @@ void GetTitleInfo(u32 category, u32 titleid, u32& version, u8* header, u8* banne
|
|||||||
u32 nread;
|
u32 nread;
|
||||||
f_read(&file, header, 0x1000, &nread);
|
f_read(&file, header, 0x1000, &nread);
|
||||||
|
|
||||||
|
if (banner)
|
||||||
|
{
|
||||||
u32 banneraddr = *(u32*)&header[0x68];
|
u32 banneraddr = *(u32*)&header[0x68];
|
||||||
if (!banneraddr)
|
if (!banneraddr)
|
||||||
{
|
{
|
||||||
@ -714,6 +763,7 @@ void GetTitleInfo(u32 category, u32 titleid, u32& version, u8* header, u8* banne
|
|||||||
f_lseek(&file, banneraddr);
|
f_lseek(&file, banneraddr);
|
||||||
f_read(&file, banner, 0x2400, &nread);
|
f_read(&file, banner, 0x2400, &nread);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
@ -916,29 +966,12 @@ bool ImportTitle(const char* appfile, u8* tmd, bool readonly)
|
|||||||
// executable
|
// executable
|
||||||
|
|
||||||
sprintf(fname, "0:/title/%08x/%08x/content/%08x.app", titleid0, titleid1, version);
|
sprintf(fname, "0:/title/%08x/%08x/content/%08x.app", titleid0, titleid1, version);
|
||||||
res = f_open(&file, fname, FA_CREATE_ALWAYS | FA_WRITE);
|
if (!ImportFile(fname, appfile))
|
||||||
if (res != FR_OK)
|
|
||||||
{
|
{
|
||||||
printf("ImportTitle: failed to create executable (%d)\n", res);
|
printf("ImportTitle: failed to create executable (%d)\n", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* app = fopen(appfile, "rb");
|
|
||||||
fseek(app, 0, SEEK_END);
|
|
||||||
u32 applen = (u32)ftell(app);
|
|
||||||
fseek(app, 0, SEEK_SET);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < applen; i += 0x200)
|
|
||||||
{
|
|
||||||
u8 data[0x200];
|
|
||||||
|
|
||||||
u32 lenread = fread(data, 1, 0x200, app);
|
|
||||||
f_write(&file, data, lenread, &nwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(app);
|
|
||||||
f_close(&file);
|
|
||||||
|
|
||||||
if (readonly) f_chmod(fname, AM_RDO, AM_RDO);
|
if (readonly) f_chmod(fname, AM_RDO, AM_RDO);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -955,4 +988,72 @@ void DeleteTitle(u32 category, u32 titleid)
|
|||||||
RemoveDir(fname);
|
RemoveDir(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetTitleDataMask(u32 category, u32 titleid)
|
||||||
|
{
|
||||||
|
u32 version;
|
||||||
|
u8 header[0x1000];
|
||||||
|
|
||||||
|
GetTitleInfo(category, titleid, version, header, nullptr);
|
||||||
|
if (version == 0xFFFFFFFF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 ret = 0;
|
||||||
|
if (*(u32*)&header[0x238] != 0) ret |= (1 << TitleData_PublicSav);
|
||||||
|
if (*(u32*)&header[0x23C] != 0) ret |= (1 << TitleData_PrivateSav);
|
||||||
|
if (header[0x1BF] & 0x04) ret |= (1 << TitleData_BannerSav);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportTitleData(u32 category, u32 titleid, int type, const char* file)
|
||||||
|
{
|
||||||
|
char fname[128];
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TitleData_PublicSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/public.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TitleData_PrivateSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/private.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TitleData_BannerSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/banner.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveFile(fname);
|
||||||
|
return ImportFile(fname, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExportTitleData(u32 category, u32 titleid, int type, const char* file)
|
||||||
|
{
|
||||||
|
char fname[128];
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TitleData_PublicSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/public.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TitleData_PrivateSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/private.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TitleData_BannerSav:
|
||||||
|
sprintf(fname, "0:/title/%08x/%08x/data/banner.sav", category, titleid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExportFile(fname, file);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,13 @@
|
|||||||
namespace DSi_NAND
|
namespace DSi_NAND
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TitleData_PublicSav,
|
||||||
|
TitleData_PrivateSav,
|
||||||
|
TitleData_BannerSav,
|
||||||
|
};
|
||||||
|
|
||||||
bool Init(FILE* nand, u8* es_keyY);
|
bool Init(FILE* nand, u8* es_keyY);
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
@ -39,6 +46,10 @@ void GetTitleInfo(u32 category, u32 titleid, u32& version, u8* header, u8* banne
|
|||||||
bool ImportTitle(const char* appfile, u8* tmd, bool readonly);
|
bool ImportTitle(const char* appfile, u8* tmd, bool readonly);
|
||||||
void DeleteTitle(u32 category, u32 titleid);
|
void DeleteTitle(u32 category, u32 titleid);
|
||||||
|
|
||||||
|
u32 GetTitleDataMask(u32 category, u32 titleid);
|
||||||
|
bool ImportTitleData(u32 category, u32 titleid, int type, const char* file);
|
||||||
|
bool ExportTitleData(u32 category, u32 titleid, int type, const char* file);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DSI_NAND_H
|
#endif // DSI_NAND_H
|
||||||
|
@ -94,6 +94,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="6" column="0" colspan="3">
|
<item row="6" column="0" colspan="3">
|
||||||
<widget class="QCheckBox" name="cbReadOnly">
|
<widget class="QCheckBox" name="cbReadOnly">
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string><html><head/><body><p>Makes the title executable and TMD read-only. Prevents DSi system utilities from deleting them.</p></body></html></string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Make title files read-only</string>
|
<string>Make title files read-only</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
@ -59,6 +60,42 @@ TitleManagerDialog::TitleManagerDialog(QWidget* parent) : QDialog(parent), ui(ne
|
|||||||
ui->btnImportTitleData->setEnabled(false);
|
ui->btnImportTitleData->setEnabled(false);
|
||||||
ui->btnExportTitleData->setEnabled(false);
|
ui->btnExportTitleData->setEnabled(false);
|
||||||
ui->btnDeleteTitle->setEnabled(false);
|
ui->btnDeleteTitle->setEnabled(false);
|
||||||
|
|
||||||
|
{
|
||||||
|
QMenu* menu = new QMenu(ui->btnImportTitleData);
|
||||||
|
|
||||||
|
actImportTitleData[0] = menu->addAction("public.sav");
|
||||||
|
actImportTitleData[0]->setData(QVariant(DSi_NAND::TitleData_PublicSav));
|
||||||
|
connect(actImportTitleData[0], &QAction::triggered, this, &TitleManagerDialog::onImportTitleData);
|
||||||
|
|
||||||
|
actImportTitleData[1] = menu->addAction("private.sav");
|
||||||
|
actImportTitleData[1]->setData(QVariant(DSi_NAND::TitleData_PrivateSav));
|
||||||
|
connect(actImportTitleData[1], &QAction::triggered, this, &TitleManagerDialog::onImportTitleData);
|
||||||
|
|
||||||
|
actImportTitleData[2] = menu->addAction("banner.sav");
|
||||||
|
actImportTitleData[2]->setData(QVariant(DSi_NAND::TitleData_BannerSav));
|
||||||
|
connect(actImportTitleData[2], &QAction::triggered, this, &TitleManagerDialog::onImportTitleData);
|
||||||
|
|
||||||
|
ui->btnImportTitleData->setMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QMenu* menu = new QMenu(ui->btnExportTitleData);
|
||||||
|
|
||||||
|
actExportTitleData[0] = menu->addAction("public.sav");
|
||||||
|
actExportTitleData[0]->setData(QVariant(DSi_NAND::TitleData_PublicSav));
|
||||||
|
connect(actExportTitleData[0], &QAction::triggered, this, &TitleManagerDialog::onExportTitleData);
|
||||||
|
|
||||||
|
actExportTitleData[1] = menu->addAction("private.sav");
|
||||||
|
actExportTitleData[1]->setData(QVariant(DSi_NAND::TitleData_PrivateSav));
|
||||||
|
connect(actExportTitleData[1], &QAction::triggered, this, &TitleManagerDialog::onExportTitleData);
|
||||||
|
|
||||||
|
actExportTitleData[2] = menu->addAction("banner.sav");
|
||||||
|
actExportTitleData[2]->setData(QVariant(DSi_NAND::TitleData_BannerSav));
|
||||||
|
connect(actExportTitleData[2], &QAction::triggered, this, &TitleManagerDialog::onExportTitleData);
|
||||||
|
|
||||||
|
ui->btnExportTitleData->setMenu(menu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleManagerDialog::~TitleManagerDialog()
|
TitleManagerDialog::~TitleManagerDialog()
|
||||||
@ -99,6 +136,9 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid)
|
|||||||
QListWidgetItem* item = new QListWidgetItem(title + QString(extra));
|
QListWidgetItem* item = new QListWidgetItem(title + QString(extra));
|
||||||
item->setIcon(icon);
|
item->setIcon(icon);
|
||||||
item->setData(Qt::UserRole, (((u64)category<<32) | (u64)titleid));
|
item->setData(Qt::UserRole, (((u64)category<<32) | (u64)titleid));
|
||||||
|
item->setData(Qt::UserRole+1, *(u32*)&header[0x238]); // public.sav size
|
||||||
|
item->setData(Qt::UserRole+2, *(u32*)&header[0x23C]); // private.sav size
|
||||||
|
item->setData(Qt::UserRole+3, (u32)((header[0x1BF] & 0x04) ? 0x4000 : 0)); // banner.sav size
|
||||||
ui->lstTitleList->addItem(item);
|
ui->lstTitleList->addItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,16 +223,6 @@ void TitleManagerDialog::onImportTitleFinished(int res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleManagerDialog::on_btnImportTitleData_clicked()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleManagerDialog::on_btnExportTitleData_clicked()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleManagerDialog::on_btnDeleteTitle_clicked()
|
void TitleManagerDialog::on_btnDeleteTitle_clicked()
|
||||||
{
|
{
|
||||||
QListWidgetItem* cur = ui->lstTitleList->currentItem();
|
QListWidgetItem* cur = ui->lstTitleList->currentItem();
|
||||||
@ -205,7 +235,7 @@ void TitleManagerDialog::on_btnDeleteTitle_clicked()
|
|||||||
QMessageBox::No) != QMessageBox::Yes)
|
QMessageBox::No) != QMessageBox::Yes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u64 titleid = cur->data(Qt::UserRole).toLongLong();
|
u64 titleid = cur->data(Qt::UserRole).toULongLong();
|
||||||
DSi_NAND::DeleteTitle((u32)(titleid >> 32), (u32)titleid);
|
DSi_NAND::DeleteTitle((u32)(titleid >> 32), (u32)titleid);
|
||||||
|
|
||||||
delete cur;
|
delete cur;
|
||||||
@ -225,7 +255,125 @@ void TitleManagerDialog::on_lstTitleList_currentItemChanged(QListWidgetItem* cur
|
|||||||
ui->btnExportTitleData->setEnabled(true);
|
ui->btnExportTitleData->setEnabled(true);
|
||||||
ui->btnDeleteTitle->setEnabled(true);
|
ui->btnDeleteTitle->setEnabled(true);
|
||||||
|
|
||||||
//
|
u32 val;
|
||||||
|
val = cur->data(Qt::UserRole+1).toUInt();
|
||||||
|
actImportTitleData[0]->setEnabled(val != 0);
|
||||||
|
actExportTitleData[0]->setEnabled(val != 0);
|
||||||
|
val = cur->data(Qt::UserRole+2).toUInt();
|
||||||
|
actImportTitleData[1]->setEnabled(val != 0);
|
||||||
|
actExportTitleData[1]->setEnabled(val != 0);
|
||||||
|
val = cur->data(Qt::UserRole+3).toUInt();
|
||||||
|
actImportTitleData[2]->setEnabled(val != 0);
|
||||||
|
actExportTitleData[2]->setEnabled(val != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleManagerDialog::onImportTitleData()
|
||||||
|
{
|
||||||
|
int type = ((QAction*)sender())->data().toInt();
|
||||||
|
|
||||||
|
QListWidgetItem* cur = ui->lstTitleList->currentItem();
|
||||||
|
if (!cur)
|
||||||
|
{
|
||||||
|
printf("what??\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 wantedsize;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case DSi_NAND::TitleData_PublicSav: wantedsize = cur->data(Qt::UserRole+1).toUInt(); break;
|
||||||
|
case DSi_NAND::TitleData_PrivateSav: wantedsize = cur->data(Qt::UserRole+2).toUInt(); break;
|
||||||
|
case DSi_NAND::TitleData_BannerSav: wantedsize = cur->data(Qt::UserRole+3).toUInt(); break;
|
||||||
|
default:
|
||||||
|
printf("what??\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString file = QFileDialog::getOpenFileName(this,
|
||||||
|
"Select file to import...",
|
||||||
|
EmuDirectory,
|
||||||
|
"Title data files (*.sav);;Any file (*.*)");
|
||||||
|
|
||||||
|
if (file.isEmpty()) return;
|
||||||
|
|
||||||
|
FILE* f = fopen(file.toStdString().c_str(), "rb");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
"Import title data - melonDS",
|
||||||
|
"Could not open data file.\nCheck that the file is accessible.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
u64 len = ftell(f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (len != wantedsize)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
"Import title data - melonDS",
|
||||||
|
QString("Cannot import this data file: size is incorrect (expected: %1 bytes).").arg(wantedsize));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 titleid = cur->data(Qt::UserRole).toULongLong();
|
||||||
|
bool res = DSi_NAND::ImportTitleData((u32)(titleid >> 32), (u32)titleid, type, file.toStdString().c_str());
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
"Import title data - melonDS",
|
||||||
|
"Failed to import the data file. Check that your NAND is accessible and valid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleManagerDialog::onExportTitleData()
|
||||||
|
{
|
||||||
|
int type = ((QAction*)sender())->data().toInt();
|
||||||
|
|
||||||
|
QListWidgetItem* cur = ui->lstTitleList->currentItem();
|
||||||
|
if (!cur)
|
||||||
|
{
|
||||||
|
printf("what??\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString exportname;
|
||||||
|
u32 wantedsize;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case DSi_NAND::TitleData_PublicSav:
|
||||||
|
exportname = "/public.sav";
|
||||||
|
wantedsize = cur->data(Qt::UserRole+1).toUInt();
|
||||||
|
break;
|
||||||
|
case DSi_NAND::TitleData_PrivateSav:
|
||||||
|
exportname = "/private.sav";
|
||||||
|
wantedsize = cur->data(Qt::UserRole+2).toUInt();
|
||||||
|
break;
|
||||||
|
case DSi_NAND::TitleData_BannerSav:
|
||||||
|
exportname = "/banner.sav";
|
||||||
|
wantedsize = cur->data(Qt::UserRole+3).toUInt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("what??\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString file = QFileDialog::getSaveFileName(this,
|
||||||
|
"Select path to export to...",
|
||||||
|
QString(EmuDirectory) + exportname,
|
||||||
|
"Title data files (*.sav);;Any file (*.*)");
|
||||||
|
|
||||||
|
if (file.isEmpty()) return;
|
||||||
|
|
||||||
|
u64 titleid = cur->data(Qt::UserRole).toULongLong();
|
||||||
|
bool res = DSi_NAND::ExportTitleData((u32)(titleid >> 32), (u32)titleid, type, file.toStdString().c_str());
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
"Export title data - melonDS",
|
||||||
|
"Failed to Export the data file. Check that the destination directory is writable.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +81,10 @@ private slots:
|
|||||||
|
|
||||||
void on_btnImportTitle_clicked();
|
void on_btnImportTitle_clicked();
|
||||||
void onImportTitleFinished(int res);
|
void onImportTitleFinished(int res);
|
||||||
void on_btnImportTitleData_clicked();
|
|
||||||
void on_btnExportTitleData_clicked();
|
|
||||||
void on_btnDeleteTitle_clicked();
|
void on_btnDeleteTitle_clicked();
|
||||||
void on_lstTitleList_currentItemChanged(QListWidgetItem* cur, QListWidgetItem* prev);
|
void on_lstTitleList_currentItemChanged(QListWidgetItem* cur, QListWidgetItem* prev);
|
||||||
|
void onImportTitleData();
|
||||||
|
void onExportTitleData();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::TitleManagerDialog* ui;
|
Ui::TitleManagerDialog* ui;
|
||||||
@ -93,8 +93,8 @@ private:
|
|||||||
u8 importTmdData[0x208];
|
u8 importTmdData[0x208];
|
||||||
bool importReadOnly;
|
bool importReadOnly;
|
||||||
|
|
||||||
QAction* importAction[3];
|
QAction* actImportTitleData[3];
|
||||||
QAction* exportAction[3];
|
QAction* actExportTitleData[3];
|
||||||
|
|
||||||
void createTitleItem(u32 category, u32 titleid);
|
void createTitleItem(u32 category, u32 titleid);
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
<string><html><head/><body><p>Import data (save, banner...) for the selected title.</p></body></html></string>
|
<string><html><head/><body><p>Import data (save, banner...) for the selected title.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Import title data...</string>
|
<string>Import title data</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -54,7 +54,7 @@
|
|||||||
<string><html><head/><body><p>Export the data (save, banner...) associated with the selected title.</p></body></html></string>
|
<string><html><head/><body><p>Export the data (save, banner...) associated with the selected title.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Export title data...</string>
|
<string>Export title data</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
Reference in New Issue
Block a user