diff --git a/src/NDS.cpp b/src/NDS.cpp index 00c7389a..df1ac9f2 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -823,6 +823,20 @@ void SetConsoleType(int type) ConsoleType = type; } +bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) +{ + if (NDSCart::LoadROM(romdata, filelength, sram, direct)) + { + Running = true; + return true; + } + else + { + printf("Failed to load ROM from archive\n"); + return false; + } +} + bool LoadROM(const char* path, const char* sram, bool direct) { if (NDSCart::LoadROM(path, sram, direct)) diff --git a/src/NDS.h b/src/NDS.h index 46a57a49..3a8875a9 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -193,6 +193,7 @@ void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, void SetConsoleType(int type); bool LoadROM(const char* path, const char* sram, bool direct); +bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); bool LoadGBAROM(const char* path, const char* sram); void LoadBIOS(); void SetupDirectBoot(); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 7395d045..d065f6ac 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -1026,6 +1026,22 @@ bool LoadROM(const char* path, const char* sram, bool direct) return LoadROMCommon(len, sram, direct); } +bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) +{ + NDS::Reset(); + + u32 len = filelength; + CartROMSize = 0x200; + while (CartROMSize < len) + CartROMSize <<= 1; + + CartROM = new u8[CartROMSize]; + memset(CartROM, 0, CartROMSize); + memcpy(CartROM, romdata, filelength); + + return LoadROMCommon(filelength, sram, direct); +} + void RelocateSave(const char* path, bool write) { // herp derp diff --git a/src/NDSCart.h b/src/NDSCart.h index 7d3f4a15..a108eb90 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -46,6 +46,7 @@ void DoSavestate(Savestate* file); void DecryptSecureArea(u8* out); bool LoadROM(const char* path, const char* sram, bool direct); +bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); void FlushSRAMFile(); diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index caac9f08..a297c70c 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -19,6 +19,9 @@ #ifndef FRONTENDUTIL_H #define FRONTENDUTIL_H +#include +#include + #include "types.h" namespace Frontend @@ -76,6 +79,7 @@ int LoadBIOS(); // load a ROM file to the specified cart slot // note: loading a ROM to the NDS slot resets emulation int LoadROM(const char* file, int slot); +int LoadROM(const QByteArray *romdata, QString archivefilename, QString romfilename, int slot); // unload the ROM loaded in the specified cart slot // simulating ejection of the cartridge diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index 9f22f5f5..46b96d1c 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + #include "FrontendUtil.h" #include "Config.h" #include "SharedConfig.h" @@ -283,6 +286,85 @@ int LoadBIOS() return Load_OK; } +int LoadROM(const QByteArray *romdata, QString archivefilename, QString romfilename, int slot) +{ + int res; + bool directboot = Config::DirectBoot != 0; + + if (Config::ConsoleType == 1 && slot == 1) + { + // cannot load a GBA ROM into a DSi + return Load_ROMLoadError; + } + + res = VerifyDSBIOS(); + if (res != Load_OK) return res; + + if (Config::ConsoleType == 1) + { + res = VerifyDSiBIOS(); + if (res != Load_OK) return res; + + res = VerifyDSiFirmware(); + if (res != Load_OK) return res; + + res = VerifyDSiNAND(); + if (res != Load_OK) return res; + + GBACart::Eject(); + ROMPath[ROMSlot_GBA][0] = '\0'; + } + else + { + res = VerifyDSFirmware(); + if (res != Load_OK) + { + if (res == Load_FirmwareNotBootable) + directboot = true; + else + return res; + } + } + + char oldpath[1024]; + char oldsram[1024]; + strncpy(oldpath, ROMPath[slot], 1024); + strncpy(oldsram, SRAMPath[slot], 1024); + + QString sramFile = QFileInfo(archivefilename).absolutePath() + QDir::separator() + QFileInfo(romfilename).completeBaseName() + ".sav"; + strncpy(SRAMPath[slot], QDir::cleanPath(sramFile).toStdString().c_str(), 1024); + strncpy(ROMPath[slot], archivefilename.toStdString().c_str(), 1024); + + NDS::SetConsoleType(Config::ConsoleType); + + if (slot == ROMSlot_NDS && NDS::LoadROM((const u8*)romdata->constData(), romdata->size(), SRAMPath[slot], directboot)) + { + SavestateLoaded = false; + + LoadCheats(); + + // Reload the inserted GBA cartridge (if any) + // TODO: report failure there?? + //if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]); + + strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety + return Load_OK; + } + /*else if (slot == ROMSlot_GBA && NDS::LoadGBAROM(ROMPath[slot], SRAMPath[slot])) + { + SavestateLoaded = false; // checkme?? + + strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety + return Load_OK; + }*/ + else + { + strncpy(ROMPath[slot], oldpath, 1024); + strncpy(SRAMPath[slot], oldsram, 1024); + return Load_ROMLoadError; + } +} + int LoadROM(const char* file, int slot) { int res; diff --git a/src/frontend/qt_sdl/ArchiveUtil.cpp b/src/frontend/qt_sdl/ArchiveUtil.cpp index 07b13a5f..470e035a 100644 --- a/src/frontend/qt_sdl/ArchiveUtil.cpp +++ b/src/frontend/qt_sdl/ArchiveUtil.cpp @@ -53,7 +53,7 @@ QVector ListArchive(const char* path) return fileList; } -QVector ExtractFileFromArchive(const char* path, const char* wantedFile) +QVector ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer) { struct archive *a = archive_read_new(); struct archive_entry *entry; @@ -67,11 +67,9 @@ QVector ExtractFileFromArchive(const char* path, const char* wantedFile { return QVector {"Err"}; } - while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - if (wantedFile == nullptr) - { - break; - } + + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) + { if (strcmp(wantedFile, archive_entry_pathname(entry)) == 0) { break; @@ -79,8 +77,8 @@ QVector ExtractFileFromArchive(const char* path, const char* wantedFile } size_t bytesToWrite = archive_entry_size(entry); - QByteArray archiveBuffer(bytesToWrite, '\0'); - ssize_t bytesRead = archive_read_data(a, archiveBuffer.data(), bytesToWrite); + romBuffer->fill(0, bytesToWrite); + ssize_t bytesRead = archive_read_data(a, romBuffer->data(), bytesToWrite); if (bytesRead < 0) { @@ -88,18 +86,9 @@ QVector ExtractFileFromArchive(const char* path, const char* wantedFile return QVector {"Err", archive_error_string(a)}; } - QString extractToFolder = QFileInfo(path).absolutePath() + "/" + QFileInfo(path).baseName(); - QDir().mkdir(extractToFolder); - - QString nameToWrite = extractToFolder + "/" + archive_entry_pathname(entry); - QFile fileToWrite(nameToWrite); - if(fileToWrite.open(QIODevice::WriteOnly)) - fileToWrite.write(archiveBuffer); - - fileToWrite.close(); archive_read_close(a); archive_read_free(a); - return QVector {nameToWrite}; + return QVector {wantedFile}; } diff --git a/src/frontend/qt_sdl/ArchiveUtil.h b/src/frontend/qt_sdl/ArchiveUtil.h index a6f404ad..40d5d36f 100644 --- a/src/frontend/qt_sdl/ArchiveUtil.h +++ b/src/frontend/qt_sdl/ArchiveUtil.h @@ -18,7 +18,7 @@ namespace Archive { QVector ListArchive(const char* path); -QVector ExtractFileFromArchive(const char* path, const char* wantedFile); +QVector ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer); } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index f0185cc9..f1bf5f4b 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1501,6 +1501,44 @@ QString MainWindow::loadErrorStr(int error) } } +void MainWindow::loadROM(QByteArray *romData, QString archiveFileName, QString romFileName) +{ + // Strip entire archive name and get folder path + strncpy(Config::LastROMFolder, QFileInfo(archiveFileName).absolutePath().toStdString().c_str(), 1024); + + int slot; int res; + /*if (!strcasecmp(ext, "gba")) + { + slot = 1; + res = Frontend::LoadROM(file, Frontend::ROMSlot_GBA); + } + else + { + slot = 0; + res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS); + }*/ + + // TODO: GBA support here! + slot = 0; + res = Frontend::LoadROM(romData, archiveFileName, romFileName, Frontend::ROMSlot_NDS); + if (res != Frontend::Load_OK) + { + QMessageBox::critical(this, + "melonDS", + loadErrorStr(res)); + emuThread->emuUnpause(); + } + else if (slot == 1) + { + // checkme + emuThread->emuUnpause(); + } + else + { + emuThread->emuRun(); + } +} + void MainWindow::loadROM(QString filename) { recentFileList.removeAll(filename); @@ -1573,28 +1611,31 @@ void MainWindow::onOpenFileArchive() { emuThread->emuPause(); - QString filename = QFileDialog::getOpenFileName(this, + QString archiveFileName = QFileDialog::getOpenFileName(this, "Open ROM Archive", Config::LastROMFolder, "Archived ROMs (*.zip *.7z *.rar *.tar *.tar.gz *.tar.xz *.tar.bz2);;Any file (*.*)"); - if (filename.isEmpty()) + if (archiveFileName.isEmpty()) { emuThread->emuUnpause(); return; } printf("Finding list of ROMs...\n"); - QVector archiveROMList = Archive::ListArchive(filename.toUtf8().constData()); + QVector archiveROMList = Archive::ListArchive(archiveFileName.toUtf8().constData()); + QByteArray *romBuffer = new QByteArray(); + QString romFileName; // file name inside archive + if (archiveROMList.size() > 2) { archiveROMList.removeFirst(); QString toLoad = QInputDialog::getItem(this, "melonDS", "The archive was found to have multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false); printf("Extracting '%s'\n", toLoad.toUtf8().constData()); - QVector extractResult = Archive::ExtractFileFromArchive(filename.toUtf8().constData(), toLoad.toUtf8().constData()); + QVector extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), toLoad.toUtf8().constData(), romBuffer); if (extractResult[0] != QString("Err")) { - filename = extractResult[0]; + romFileName = extractResult[0]; } else { @@ -1604,10 +1645,10 @@ void MainWindow::onOpenFileArchive() else if (archiveROMList.size() == 2) { printf("Extracting the only ROM in archive\n"); - QVector extractResult = Archive::ExtractFileFromArchive(filename.toUtf8().constData(), nullptr); + QVector extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), archiveROMList.at(1).toUtf8().constData(), romBuffer); if (extractResult[0] != QString("Err")) { - filename = extractResult[0]; + romFileName = extractResult[0]; } else { @@ -1623,7 +1664,8 @@ void MainWindow::onOpenFileArchive() QMessageBox::critical(this, "melonDS", "The archive could not be read. It may be corrupt or you don't have the permissions."); } - loadROM(filename); + loadROM(romBuffer, archiveFileName, romFileName); + delete romBuffer; } void MainWindow::onClearRecentFiles() diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 97f514bb..591e612d 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -243,6 +243,7 @@ private: QMenu *recentMenu; void updateRecentFilesMenu(); void loadROM(QString filename); + void loadROM(QByteArray *romData, QString archiveFileName, QString romFileName); void createScreenPanel();