Skip to content

Commit

Permalink
RMG: add zip file support
Browse files Browse the repository at this point in the history
  • Loading branch information
Rosalie241 committed Oct 17, 2021
1 parent 4f8ede0 commit e91e762
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 15 deletions.
5 changes: 3 additions & 2 deletions Source/RMG/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)

find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(MINIZIP REQUIRED minizip)

configure_file(Config.hpp.in Config.hpp)

Expand Down Expand Up @@ -59,9 +60,9 @@ else()
add_executable(RMG ${RMG_SOURCES})
endif()

target_link_libraries(RMG ${SDL2_LIBRARIES})
target_link_libraries(RMG ${SDL2_LIBRARIES} ${MINIZIP_LIBRARIES})

target_include_directories(RMG PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${SDL2_INCLUDE_DIRS})
target_include_directories(RMG PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${SDL2_INCLUDE_DIRS} ${MINIZIP_INCLUDE_DIRS})

if(UNIX)
target_link_libraries(RMG dl)
Expand Down
178 changes: 170 additions & 8 deletions Source/RMG/M64P/Wrapper/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include "../api/version.h"
#include "Config.hpp"
#include "Plugin.hpp"

#include <QDir>
#include <unzip.h>

using namespace M64P::Wrapper;

Expand Down Expand Up @@ -727,33 +729,193 @@ bool Core::rom_Open(QString file, bool overlay = true)
QByteArray buffer;
QFile qFile(file);

if (!qFile.open(QIODevice::ReadOnly))
{
this->error_Message = "Core::rom_Open: QFile::open Failed";
return false;
void* bufferData = nullptr;
int bufferDataSize = 0;
bool clearByteArray = false;

if (file.endsWith(".zip", Qt::CaseInsensitive))
{ // try to extract ROM from archive
if (!this->rom_Unzip(file, &bufferData, &bufferDataSize))
{
return false;
}
}
else
{ // read file normally
if (!qFile.open(QIODevice::ReadOnly))
{
this->error_Message = "Core::rom_Open: QFile::open Failed";
return false;
}

buffer = qFile.readAll();
buffer = qFile.readAll();
bufferDataSize = buffer.size();
bufferData = buffer.data();
qFile.close();

ret = M64P::Core.DoCommand(M64CMD_ROM_OPEN, buffer.size(), buffer.data());
clearByteArray = true;
}

ret = M64P::Core.DoCommand(M64CMD_ROM_OPEN, bufferDataSize, bufferData);
if (ret != M64ERR_SUCCESS)
{
this->error_Message = "Core::rom_Open: M64P::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
this->error_Message += M64P::Core.ErrorMessage(ret);
}

buffer.clear();
qFile.close();
if (clearByteArray)
{
buffer.clear();
}
else
{
free(bufferData);
}

if (ret != M64ERR_SUCCESS)
{
return false;
}

if (overlay)
{
return this->rom_ApplyOverlay();
}

return true;
}

#define UNZIP_READ_SIZE 67108860 /* 64 MiB */

bool Core::rom_Unzip(QString file, void** outData, int* outDataSize)
{
unzFile zipFile;
unz_global_info zipInfo;

zipFile = unzOpen(file.toStdString().c_str());
if (zipFile == nullptr)
{
this->error_Message = "Core::rom_Unzip: unzOpen Failed!";
return false;
}

if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
{
this->error_Message = "Core::rom_Unzip: unzGetGlobalInfo Failed!";
return false;
}

for (int i = 0; i < zipInfo.number_entry; i++)
{
unz_file_info fileInfo;
char fileName[PATH_MAX];

// if we can't retrieve file info,
// skip the file
if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, PATH_MAX, nullptr, 0, nullptr, 0) != UNZ_OK)
{
continue;
}

// make sure file has supported file format,
// if it does, read it in memory
QString qFileName(fileName);
if (qFileName.endsWith(".z64", Qt::CaseInsensitive) ||
qFileName.endsWith(".v64", Qt::CaseInsensitive) ||
qFileName.endsWith(".n64", Qt::CaseInsensitive))
{
void* buffer;
int dataSize = UNZIP_READ_SIZE;
int total_bytes_read = 0;
int bytes_read = 0;

buffer = malloc(UNZIP_READ_SIZE);
if (buffer == nullptr)
{
this->error_Message = "Core::rom_Unzip: malloc Failed!";
return false;
}

*outData = malloc(UNZIP_READ_SIZE);
if (*outData == nullptr)
{
free(buffer);
this->error_Message = "Core::rom_Unzip: malloc Failed!";
return false;
}

if (unzOpenCurrentFile(zipFile) != UNZ_OK)
{
free(buffer);
free(*outData);
this->error_Message = "Core::rom_Unzip: unzOpenCurrentFile Failed!";
return false;
}

do
{
bytes_read = unzReadCurrentFile(zipFile, buffer, UNZIP_READ_SIZE);
if (bytes_read < 0)
{
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
free(buffer);
free(*outData);
this->error_Message = "Core::rom_Unzip: unzReadCurrentFile Failed: ";
this->error_Message += QString::number(bytes_read);
return false;
}

if (bytes_read > 0)
{
if (total_bytes_read + bytes_read > dataSize)
{
*outData = realloc(*outData, total_bytes_read + bytes_read);
dataSize += bytes_read;
if (*outData == nullptr)
{
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
free(buffer);
free(*outData);
this->error_Message = "Core::rom_Unzip: realloc Failed!";
return false;
}
}

memcpy((void*)((int*)*outData + total_bytes_read), buffer, bytes_read);
total_bytes_read += bytes_read;
}
} while (bytes_read > 0);

*outDataSize = total_bytes_read;
unzCloseCurrentFile(zipFile);
unzClose(zipFile);
free(buffer);
return true;
}

// break when we've iterated over all entries
if ((i + 1) >= zipInfo.number_entry)
{
break;
}

// move to next file
if (unzGoToNextFile(zipFile) != UNZ_OK)
{
unzClose(zipFile);
this->error_Message = "Core::rom_Unzip: unzGoToNextFile Failed!";
return false;
}
}

this->error_Message = "Core::rom_Unzip: no valid ROMs found in ZIP!";
unzClose(zipFile);
return false;
}


bool Core::rom_ApplyPluginOverlay(void)
{
bool ret;
Expand Down
2 changes: 1 addition & 1 deletion Source/RMG/M64P/Wrapper/Core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ class Core : public QObject
RomInfo_t rom_Info;

bool rom_Open(QString, bool);
bool rom_Unzip(QString, void**, int*);
bool rom_ApplyPluginOverlay(void);
bool rom_HasPluginOverlay(QString);
bool rom_ApplyOverlay(void);
bool rom_Close(void);


static void core_DebugCallback(void *, int, const char *);
static void core_StateCallback(void *, m64p_core_param, int);

Expand Down
4 changes: 2 additions & 2 deletions Source/RMG/Thread/RomSearcherThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ void RomSearcherThread::rom_Search(QString directory)
filter << "*.N64";
filter << "*.Z64";
filter << "*.V64";
filter << "*.ndd";
filter << "*.NDD";
filter << "*.D64";

filter << "*.ZIP";

QFileInfoList fileList = dir.entryInfoList(filter, QDir::Files);
QFileInfo fileInfo;
Expand Down
4 changes: 2 additions & 2 deletions Source/RMG/UserInterface/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ void MainWindow::on_Action_File_OpenRom(void)
QString dir;

dialog.setFileMode(QFileDialog::FileMode::ExistingFile);
dialog.setNameFilter("N64 ROMs & Disks (*.n64 *.z64 *.v64 *.ndd *.d64)");
dialog.setNameFilter("N64 ROMs & Disks (*.n64 *.z64 *.v64 *.ndd *.d64 *.zip)");

ret = dialog.exec();
if (!ret)
Expand Down Expand Up @@ -822,7 +822,7 @@ void MainWindow::on_Action_File_OpenCombo(void)
QString dir, cartRom, diskRom;

dialog.setFileMode(QFileDialog::FileMode::ExistingFile);
dialog.setNameFilter("N64 ROMs (*.n64 *.z64 *.v64)");
dialog.setNameFilter("N64 ROMs (*.n64 *.z64 *.v64 *.zip)");

ret = dialog.exec();
if (!ret)
Expand Down

0 comments on commit e91e762

Please sign in to comment.