diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GBACart.cpp | 61 | ||||
-rw-r--r-- | src/GBACart.h | 1 | ||||
-rw-r--r-- | src/NDS.cpp | 27 | ||||
-rw-r--r-- | src/NDS.h | 2 | ||||
-rw-r--r-- | src/NDSCart.cpp | 86 | ||||
-rw-r--r-- | src/NDSCart.h | 1 | ||||
-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 |
13 files changed, 449 insertions, 108 deletions
diff --git a/src/GBACart.cpp b/src/GBACart.cpp index 4d44d3a..9188408 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -620,6 +620,32 @@ void DoSavestate(Savestate* file) if (HasSolarSensor) GBACart_SolarSensor::DoSavestate(file);
}
+void LoadROMCommon(const char *sram)
+{
+ char gamecode[5] = { '\0' };
+ memcpy(&gamecode, CartROM + 0xAC, 4);
+ printf("Game code: %s\n", gamecode);
+
+ for (int i = 0; i < sizeof(SOLAR_SENSOR_GAMECODES)/sizeof(SOLAR_SENSOR_GAMECODES[0]); i++)
+ {
+ if (strcmp(gamecode, SOLAR_SENSOR_GAMECODES[i]) == 0) HasSolarSensor = true;
+ }
+
+ if (HasSolarSensor)
+ {
+ printf("GBA solar sensor support detected!\n");
+ }
+
+ CartCRC = CRC32(CartROM, CartROMSize);
+ printf("ROM CRC32: %08X\n", CartCRC);
+
+ CartInserted = true;
+
+ // save
+ printf("Save file: %s\n", sram);
+ GBACart_SRAM::LoadSave(sram);
+}
+
bool LoadROM(const char* path, const char* sram)
{
FILE* f = Platform::OpenFile(path, "rb");
@@ -640,36 +666,27 @@ bool LoadROM(const char* path, const char* sram) while (CartROMSize < len)
CartROMSize <<= 1;
- char gamecode[5] = { '\0' };
- fseek(f, 0xAC, SEEK_SET);
- fread(&gamecode, 1, 4, f);
- printf("Game code: %s\n", gamecode);
-
- for (int i = 0; i < sizeof(SOLAR_SENSOR_GAMECODES)/sizeof(SOLAR_SENSOR_GAMECODES[0]); i++)
- {
- if (strcmp(gamecode, SOLAR_SENSOR_GAMECODES[i]) == 0) HasSolarSensor = true;
- }
-
- if (HasSolarSensor)
- {
- printf("GBA solar sensor support detected!\n");
- }
-
CartROM = new u8[CartROMSize];
memset(CartROM, 0, CartROMSize);
fseek(f, 0, SEEK_SET);
fread(CartROM, 1, len, f);
-
fclose(f);
- CartCRC = CRC32(CartROM, CartROMSize);
- printf("ROM CRC32: %08X\n", CartCRC);
+ LoadROMCommon(sram);
- CartInserted = true;
+ return true;
+}
- // save
- printf("Save file: %s\n", sram);
- GBACart_SRAM::LoadSave(sram);
+bool LoadROM(const u8* romdata, u32 filelength, const char *sram)
+{
+ CartROMSize = 0x200;
+ while (CartROMSize < filelength)
+ CartROMSize <<= 1;
+
+ CartROM = new u8[CartROMSize];
+ memcpy(CartROM, romdata, filelength);
+
+ LoadROMCommon(sram);
return true;
}
diff --git a/src/GBACart.h b/src/GBACart.h index 96a05b8..f976e6d 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -66,6 +66,7 @@ void Eject(); void DoSavestate(Savestate* file);
bool LoadROM(const char* path, const char* sram);
+bool LoadROM(const u8* romdata, u32 filelength, const char *sram);
void RelocateSave(const char* path, bool write);
void WriteGPIO(u32 addr, u16 val);
diff --git a/src/NDS.cpp b/src/NDS.cpp index df3c103..d0346a5 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -830,6 +830,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)) @@ -857,6 +871,19 @@ bool LoadGBAROM(const char* path, const char* sram) } } +bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram) +{ + if (GBACart::LoadROM(romdata, filelength, sram)) + { + return true; + } + else + { + printf("Failed to load ROM %s from archive\n", filename); + return false; + } +} + void LoadBIOS() { Reset(); @@ -197,7 +197,9 @@ 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); +bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram); void LoadBIOS(); void SetupDirectBoot(); void RelocateSave(const char* path, bool write); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 0765288..ae051bd 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -885,46 +885,15 @@ void DecryptSecureArea(u8* out) } } - -bool LoadROM(const char* path, const char* sram, bool direct) +bool LoadROMCommon(u32 filelength, const char *sram, bool direct) { - // TODO: streaming mode? for really big ROMs or systems with limited RAM - // for now we're lazy - // also TODO: validate what we're loading!! - - FILE* f = Platform::OpenFile(path, "rb"); - if (!f) - { - return false; - } - - NDS::Reset(); - - fseek(f, 0, SEEK_END); - u32 len = (u32)ftell(f); - - CartROMSize = 0x200; - while (CartROMSize < len) - CartROMSize <<= 1; - u32 gamecode; - fseek(f, 0x0C, SEEK_SET); - fread(&gamecode, 4, 1, f); + memcpy(&gamecode, CartROM + 0x0C, 4); printf("Game code: %c%c%c%c\n", gamecode&0xFF, (gamecode>>8)&0xFF, (gamecode>>16)&0xFF, gamecode>>24); - u8 unitcode; - fseek(f, 0x12, SEEK_SET); - fread(&unitcode, 1, 1, f); + u8 unitcode = CartROM[0x12]; CartIsDSi = (unitcode & 0x02) != 0; - CartROM = new u8[CartROMSize]; - memset(CartROM, 0, CartROMSize); - fseek(f, 0, SEEK_SET); - fread(CartROM, 1, len, f); - - fclose(f); - //CartROM = f; - ROMListEntry romparams; if (!ReadROMParams(gamecode, &romparams)) { @@ -941,7 +910,7 @@ bool LoadROM(const char* path, const char* sram, bool direct) else printf("ROM entry: %08X %08X\n", romparams.ROMSize, romparams.SaveMemType); - if (romparams.ROMSize != len) printf("!! bad ROM size %d (expected %d) rounded to %d\n", len, romparams.ROMSize, CartROMSize); + if (romparams.ROMSize != filelength) printf("!! bad ROM size %d (expected %d) rounded to %d\n", filelength, romparams.ROMSize, CartROMSize); // generate a ROM ID // note: most games don't check the actual value @@ -1026,6 +995,53 @@ bool LoadROM(const char* path, const char* sram, bool direct) return true; } +bool LoadROM(const char* path, const char* sram, bool direct) +{ + // TODO: streaming mode? for really big ROMs or systems with limited RAM + // for now we're lazy + // also TODO: validate what we're loading!! + + FILE* f = Platform::OpenFile(path, "rb"); + if (!f) + { + return false; + } + + NDS::Reset(); + + fseek(f, 0, SEEK_END); + u32 len = (u32)ftell(f); + + CartROMSize = 0x200; + while (CartROMSize < len) + CartROMSize <<= 1; + + CartROM = new u8[CartROMSize]; + memset(CartROM, 0, CartROMSize); + fseek(f, 0, SEEK_SET); + fread(CartROM, 1, len, f); + + fclose(f); + + 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 7d3f4a1..a108eb9 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 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(); |