diff options
Diffstat (limited to 'src/frontend')
-rw-r--r-- | src/frontend/FrontendUtil.h | 3 | ||||
-rw-r--r-- | src/frontend/Util_ROM.cpp | 170 | ||||
-rw-r--r-- | src/frontend/qt_sdl/ArchiveUtil.cpp | 47 | ||||
-rw-r--r-- | src/frontend/qt_sdl/ArchiveUtil.h | 3 | ||||
-rw-r--r-- | src/frontend/qt_sdl/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.cpp | 152 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.h | 3 |
7 files changed, 328 insertions, 51 deletions
diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 584250b..83749d3 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -63,6 +63,8 @@ extern char ROMPath [ROMSlot_MAX][1024]; extern char SRAMPath[ROMSlot_MAX][1024]; extern bool SavestateLoaded; +// Stores type of nds rom i.e. nds/srl/dsi. Should be updated everytime an NDS rom is loaded from an archive +extern char NDSROMExtension[4]; // initialize the ROM handling utility void Init_ROM(); @@ -76,6 +78,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 u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, 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 065b319..5da7330 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -19,6 +19,9 @@ #include <stdio.h> #include <string.h> +#ifdef ARCHIVE_SUPPORT_ENABLED +#include "ArchiveUtil.h" +#endif #include "FrontendUtil.h" #include "Config.h" #include "SharedConfig.h" @@ -38,6 +41,8 @@ char ROMPath [ROMSlot_MAX][1024]; char SRAMPath [ROMSlot_MAX][1024]; char PrevSRAMPath[ROMSlot_MAX][1024]; // for savestate 'undo load' +char NDSROMExtension[4]; + bool SavestateLoaded; ARCodeFile* CheatFile; @@ -295,6 +300,84 @@ int LoadBIOS() return Load_OK; } +int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, 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 = SetupDSiNAND(); + 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); + + strncpy(SRAMPath[slot], sramfilename, 1024); + strncpy(ROMPath[slot], archivefilename, 1024); + + NDS::SetConsoleType(Config::ConsoleType); + + if (slot == ROMSlot_NDS && NDS::LoadROM(romdata, romlength, 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(romdata, romlength, romfilename, 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) { DSi::CloseDSiNAND(); @@ -440,16 +523,76 @@ int Reset() } else { - SetupSRAMPath(0); - if (!NDS::LoadROM(ROMPath[ROMSlot_NDS], SRAMPath[ROMSlot_NDS], directboot)) - return Load_ROMLoadError; + char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_NDS]); + strncpy(ext, ROMPath[ROMSlot_NDS] + _len - 4, 4); + + if(!strncmp(ext, ".nds", 4) || !strncmp(ext, ".srl", 4) || !strncmp(ext, ".dsi", 4)) + { + SetupSRAMPath(0); + if (!NDS::LoadROM(ROMPath[ROMSlot_NDS], SRAMPath[ROMSlot_NDS], directboot)) + return Load_ROMLoadError; + } +#ifdef ARCHIVE_SUPPORT_ENABLED + else + { + u8 *romdata = nullptr; u32 romlen; + char romfilename[1024] = {0}, sramfilename[1024]; + strncpy(sramfilename, SRAMPath[ROMSlot_NDS], 1024); // Use existing SRAMPath + + int pos = strlen(sramfilename) - 1; + while(pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\') + --pos; + + strncpy(romfilename, &sramfilename[pos + 1], 1024); + strncpy(&romfilename[strlen(romfilename) - 3], NDSROMExtension, 3); // extension could be nds, srl or dsi + printf("RESET loading from archive : %s\n", romfilename); + romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_NDS], romfilename, &romdata); + if(!romdata) + return Load_ROMLoadError; + + bool ok = NDS::LoadROM(romdata, romlen, sramfilename, directboot); + delete romdata; + if(!ok) + return Load_ROMLoadError; + } +#endif } if (ROMPath[ROMSlot_GBA][0] != '\0') { - SetupSRAMPath(1); - if (!NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA])) - return Load_ROMLoadError; + char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_GBA]); + strncpy(ext, ROMPath[ROMSlot_NDS] + _len - 4, 4); + + if(!strncmp(ext, ".gba", 4)) + { + SetupSRAMPath(1); + if (!NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA])) + return Load_ROMLoadError; + } +#ifdef ARCHIVE_SUPPORT_ENABLED + else + { + u8 *romdata = nullptr; u32 romlen; + char romfilename[1024] = {0}, sramfilename[1024]; + strncpy(sramfilename, SRAMPath[ROMSlot_GBA], 1024); // Use existing SRAMPath + + int pos = strlen(sramfilename) - 1; + while(pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\') + --pos; + + strncpy(romfilename, &sramfilename[pos + 1], 1024); + strncpy(&romfilename[strlen(romfilename) - 3], "gba", 3); + printf("RESET loading from archive : %s\n", romfilename); + romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_GBA], romfilename, &romdata); + if(!romdata) + return Load_ROMLoadError; + + bool ok = NDS::LoadGBAROM(romdata, romlen, romfilename, SRAMPath[ROMSlot_GBA]); + delete romdata; + if(!ok) + return Load_ROMLoadError; + } +#endif } LoadCheats(); @@ -472,15 +615,24 @@ void GetSavestateName(int slot, char* filename, int len) } else { - int l = strlen(ROMPath[ROMSlot_NDS]); + char *rompath; + char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_NDS]); + strncpy(ext, ROMPath[ROMSlot_NDS] + _len - 4, 4); + + if(!strncmp(ext, ".nds", 4) || !strncmp(ext, ".srl", 4) || !strncmp(ext, ".dsi", 4)) + rompath = ROMPath[ROMSlot_NDS]; + else + rompath = SRAMPath[ROMSlot_NDS]; // If archive, construct ssname from sram file + + int l = strlen(rompath); pos = l; - while (ROMPath[ROMSlot_NDS][pos] != '.' && pos > 0) pos--; + while (rompath[pos] != '.' && pos > 0) pos--; if (pos == 0) pos = l; // avoid buffer overflow. shoddy if (pos > len-5) pos = len-5; - strncpy(&filename[0], ROMPath[ROMSlot_NDS], pos); + strncpy(&filename[0], rompath, pos); } strcpy(&filename[pos], ".ml"); filename[pos+3] = '0'+slot; diff --git a/src/frontend/qt_sdl/ArchiveUtil.cpp b/src/frontend/qt_sdl/ArchiveUtil.cpp index ba6e4b6..c1f2fc1 100644 --- a/src/frontend/qt_sdl/ArchiveUtil.cpp +++ b/src/frontend/qt_sdl/ArchiveUtil.cpp @@ -18,11 +18,6 @@ #include "ArchiveUtil.h" -#ifdef _WIN32 - #include <direct.h> - #define mkdir(dir, mode) _mkdir(dir) -#endif - namespace Archive { @@ -58,7 +53,7 @@ QVector<QString> ListArchive(const char* path) return fileList; } -QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile) +QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer) { struct archive *a = archive_read_new(); struct archive_entry *entry; @@ -72,38 +67,46 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile { return QVector<QString> {"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; } } + size_t bytesToWrite = archive_entry_size(entry); - auto archiveBuffer = std::make_unique<u8[]>(bytesToWrite); - ssize_t bytesRead = archive_read_data(a, archiveBuffer.get(), bytesToWrite); + romBuffer->fill(0, bytesToWrite); + ssize_t bytesRead = archive_read_data(a, romBuffer->data(), bytesToWrite); + if (bytesRead < 0) { printf(archive_error_string(a)); - archiveBuffer.reset(nullptr); return QVector<QString> {"Err", archive_error_string(a)}; } - QString nameToWrite = QFileInfo(path).absolutePath() + "/" + QFileInfo(path).baseName() + "/" + archive_entry_pathname(entry); - mkdir(QFileInfo(path).baseName().toUtf8().constData(), 600); // Create directory otherwise fopen will not open the file - FILE* fileToWrite = fopen(nameToWrite.toUtf8().constData(), "wb"); - fwrite((char*)archiveBuffer.get(), bytesToWrite, 1, fileToWrite); - fclose(fileToWrite); - - archiveBuffer.reset(nullptr); archive_read_close(a); archive_read_free(a); - return QVector<QString> {nameToWrite}; + return QVector<QString> {wantedFile}; } +u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata) +{ + QByteArray romBuffer; + QVector<QString> extractResult = ExtractFileFromArchive(path, wantedFile, &romBuffer); + + if(extractResult[0] == "Err") + { + return 0; + } + + u32 len = romBuffer.size(); + *romdata = new u8[romBuffer.size()]; + memcpy(*romdata, romBuffer.data(), len); + + return len; +} } diff --git a/src/frontend/qt_sdl/ArchiveUtil.h b/src/frontend/qt_sdl/ArchiveUtil.h index a6f404a..3095f07 100644 --- a/src/frontend/qt_sdl/ArchiveUtil.h +++ b/src/frontend/qt_sdl/ArchiveUtil.h @@ -18,7 +18,8 @@ namespace Archive { QVector<QString> ListArchive(const char* path); -QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile); +QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer); +u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata); } diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 237ccca..612c3fd 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -63,6 +63,7 @@ if (APPLE) list(APPEND CMAKE_PREFIX_PATH "${LIBARCHIVE_DIR}") endif() pkg_check_modules(LIBARCHIVE REQUIRED libarchive) +add_compile_definitions(ARCHIVE_SUPPORT_ENABLED) if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL Release)) add_executable(melonDS WIN32 ${SOURCES_QT_SDL}) diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index f64494d..c5ce692 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1453,10 +1453,15 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event) if (urls.count() > 1) return; // not handling more than one file at once QString filename = urls.at(0).toLocalFile(); - QString ext = filename.right(3); - if (ext == "nds" || ext == "srl" || ext == "dsi" || ext == "gba") - event->acceptProposedAction(); + QStringList acceptedExts{".nds", ".srl", ".dsi", ".gba", ".rar", + ".zip", ".7z", ".tar", ".tar.gz", ".tar.xz", ".tar.bz2"}; + + for(const QString &ext : acceptedExts) + { + if(filename.endsWith(ext)) + event->acceptProposedAction(); + } } void MainWindow::dropEvent(QDropEvent* event) @@ -1471,6 +1476,10 @@ void MainWindow::dropEvent(QDropEvent* event) QString filename = urls.at(0).toLocalFile(); QString ext = filename.right(3); + recentFileList.removeAll(filename); + recentFileList.prepend(filename); + updateRecentFilesMenu(); + char _filename[1024]; strncpy(_filename, filename.toStdString().c_str(), 1023); _filename[1023] = '\0'; @@ -1480,11 +1489,32 @@ void MainWindow::dropEvent(QDropEvent* event) slot = 1; res = Frontend::LoadROM(_filename, Frontend::ROMSlot_GBA); } - else + else if(ext == "nds" || ext == "srl" || ext == "dsi") { slot = 0; res = Frontend::LoadROM(_filename, Frontend::ROMSlot_NDS); } + else + { + QByteArray romBuffer; + QString romFileName = pickAndExtractFileFromArchive(_filename, &romBuffer); + if(romFileName.isEmpty()) + { + res = Frontend::Load_ROMLoadError; + } + else + { + slot = (romFileName.endsWith(".gba") ? 1 : 0); + QString sramFileName = QFileInfo(_filename).absolutePath() + QDir::separator() + QFileInfo(romFileName).completeBaseName() + ".sav"; + + if(slot == 0) + strncpy(Frontend::NDSROMExtension, QFileInfo(romFileName).suffix().toStdString().c_str(), 4); + + res = Frontend::LoadROM((const u8*)romBuffer.constData(), romBuffer.size(), + _filename, romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(), + slot); + } + } if (res != Frontend::Load_OK) { @@ -1548,6 +1578,54 @@ QString MainWindow::loadErrorStr(int error) } } +void MainWindow::loadROM(QByteArray *romData, QString archiveFileName, QString romFileName) +{ + recentFileList.removeAll(archiveFileName); + recentFileList.prepend(archiveFileName); + updateRecentFilesMenu(); + + // Strip entire archive name and get folder path + strncpy(Config::LastROMFolder, QFileInfo(archiveFileName).absolutePath().toStdString().c_str(), 1024); + + QString sramFileName = QFileInfo(archiveFileName).absolutePath() + QDir::separator() + QFileInfo(romFileName).completeBaseName() + ".sav"; + + int slot; int res; + if (romFileName.endsWith("gba")) + { + slot = 1; + res = Frontend::LoadROM((const u8*)romData->constData(), romData->size(), + archiveFileName.toStdString().c_str(), + romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(), + Frontend::ROMSlot_GBA); + } + else + { + strncpy(Frontend::NDSROMExtension, QFileInfo(romFileName).suffix().toStdString().c_str(), 4); + slot = 0; + res = Frontend::LoadROM((const u8*)romData->constData(), romData->size(), + archiveFileName.toStdString().c_str(), + romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(), + 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); @@ -1620,43 +1698,62 @@ 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; } + QByteArray romBuffer; + QString romFileName = pickAndExtractFileFromArchive(archiveFileName, &romBuffer); + if(!romFileName.isEmpty()) + { + loadROM(&romBuffer, archiveFileName, romFileName); + } +} + +QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer) +{ printf("Finding list of ROMs...\n"); - QVector<QString> archiveROMList = Archive::ListArchive(filename.toUtf8().constData()); + QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName.toUtf8().constData()); + + + QString romFileName; // file name inside archive + if (archiveROMList.size() > 2) { archiveROMList.removeFirst(); + + bool ok; 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); + "The archive was found to have multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false, &ok); + if(!ok) // User clicked on cancel + return QString(); + printf("Extracting '%s'\n", toLoad.toUtf8().constData()); - QVector<QString> extractResult = Archive::ExtractFileFromArchive(filename.toUtf8().constData(), toLoad.toUtf8().constData()); + QVector<QString> extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), toLoad.toUtf8().constData(), romBuffer); if (extractResult[0] != QString("Err")) { - filename = extractResult[0]; + romFileName = extractResult[0]; } - else + else { QMessageBox::critical(this, "melonDS", QString("There was an error while trying to extract the ROM from the archive: ") + extractResult[1]); } - } + } else if (archiveROMList.size() == 2) - { + { printf("Extracting the only ROM in archive\n"); - QVector<QString> extractResult = Archive::ExtractFileFromArchive(filename.toUtf8().constData(), nullptr); + QVector<QString> extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), archiveROMList.at(1).toUtf8().constData(), romBuffer); if (extractResult[0] != QString("Err")) { - filename = extractResult[0]; + romFileName = extractResult[0]; } - else + else { QMessageBox::critical(this, "melonDS", QString("There was an error while trying to extract the ROM from the archive: ") + extractResult[1]); } @@ -1670,7 +1767,7 @@ 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); + return romFileName; } void MainWindow::onClearRecentFiles() @@ -1705,9 +1802,26 @@ void MainWindow::updateRecentFilesMenu() void MainWindow::onClickRecentFile() { - emuThread->emuPause(); QAction *act = (QAction *)sender(); - loadROM(act->data().toString()); + QString fileName = act->data().toString(); + + if(fileName.endsWith(".gba") || fileName.endsWith(".nds") || fileName.endsWith(".srl") || fileName.endsWith(".dsi")) + { + emuThread->emuPause(); + loadROM(fileName); + } + else + { + // Archives + QString archiveFileName = fileName; + QByteArray romBuffer; + QString romFileName = MainWindow::pickAndExtractFileFromArchive(archiveFileName, &romBuffer); + if(!romFileName.isEmpty()) + { + emuThread->emuPause(); + loadROM(&romBuffer, archiveFileName, romFileName); + } + } } void MainWindow::onBootFirmware() diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index ba67401..9ab4c2a 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -255,6 +255,9 @@ private: QMenu *recentMenu; void updateRecentFilesMenu(); void loadROM(QString filename); + void loadROM(QByteArray *romData, QString archiveFileName, QString romFileName); + + QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer); void createScreenPanel(); |