aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/FrontendUtil.h3
-rw-r--r--src/frontend/Util_ROM.cpp170
-rw-r--r--src/frontend/qt_sdl/ArchiveUtil.cpp47
-rw-r--r--src/frontend/qt_sdl/ArchiveUtil.h3
-rw-r--r--src/frontend/qt_sdl/CMakeLists.txt1
-rw-r--r--src/frontend/qt_sdl/main.cpp152
-rw-r--r--src/frontend/qt_sdl/main.h3
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();