mirror of https://github.com/mgba-emu/mgba.git
VFS: Support using minizip for zip
This commit is contained in:
parent
dd91b689a2
commit
96bc0be963
|
@ -11,7 +11,7 @@ set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugg
|
|||
set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support")
|
||||
set(USE_ZLIB ON CACHE BOOL "Whether or not to enable zlib support")
|
||||
set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support")
|
||||
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable ZIP support")
|
||||
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
|
||||
set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support")
|
||||
set(USE_BLIP ON CACHE BOOL "Whether or not to enable blip_buf support")
|
||||
set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support")
|
||||
|
@ -408,6 +408,10 @@ if(USE_LIBZIP)
|
|||
list(APPEND FEATURES LIBZIP)
|
||||
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2")
|
||||
elseif(USE_ZLIB)
|
||||
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c
|
||||
${CMAKE_SOURCE_DIR}/src/third-party/zlib/contrib/minizip/ioapi.c
|
||||
${CMAKE_SOURCE_DIR}/src/third-party/zlib/contrib/minizip/unzip.c)
|
||||
endif()
|
||||
|
||||
if (USE_LZMA)
|
||||
|
@ -602,7 +606,6 @@ message(STATUS " GDB stub: ${USE_GDB_STUB}")
|
|||
message(STATUS " Video recording: ${USE_FFMPEG}")
|
||||
message(STATUS " GIF recording: ${USE_MAGICK}")
|
||||
message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}")
|
||||
message(STATUS " ZIP support: ${USE_LIBZIP}")
|
||||
message(STATUS " 7-Zip support: ${USE_LZMA}")
|
||||
message(STATUS " Better audio resampling: ${USE_BLIP}")
|
||||
message(STATUS "Frontend summary:")
|
||||
|
|
|
@ -98,7 +98,7 @@ struct VFile* VFileOpen(const char* path, int flags) {
|
|||
|
||||
struct VDir* VDirOpenArchive(const char* path) {
|
||||
struct VDir* dir = 0;
|
||||
#if USE_LIBZIP
|
||||
#if defined(USE_LIBZIP) || defined(USE_ZLIB)
|
||||
if (!dir) {
|
||||
dir = VDirOpenZip(path, 0);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ struct VFile* VFileFromFILE(FILE* file);
|
|||
struct VDir* VDirOpen(const char* path);
|
||||
struct VDir* VDirOpenArchive(const char* path);
|
||||
|
||||
#ifdef USE_LIBZIP
|
||||
#if defined(USE_LIBZIP) || defined(USE_ZLIB)
|
||||
struct VDir* VDirOpenZip(const char* path, int flags);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,11 +8,6 @@
|
|||
#ifdef USE_LIBZIP
|
||||
#include <zip.h>
|
||||
|
||||
|
||||
enum {
|
||||
BLOCK_SIZE = 1024
|
||||
};
|
||||
|
||||
struct VDirEntryZip {
|
||||
struct VDirEntry d;
|
||||
struct zip* z;
|
||||
|
@ -35,6 +30,35 @@ struct VFileZip {
|
|||
size_t fileSize;
|
||||
};
|
||||
|
||||
enum {
|
||||
BLOCK_SIZE = 1024
|
||||
};
|
||||
#else
|
||||
#include "third-party/zlib/contrib/minizip/unzip.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
struct VDirEntryZip {
|
||||
struct VDirEntry d;
|
||||
char name[PATH_MAX];
|
||||
size_t fileSize;
|
||||
unzFile z;
|
||||
};
|
||||
|
||||
struct VDirZip {
|
||||
struct VDir d;
|
||||
unzFile z;
|
||||
struct VDirEntryZip dirent;
|
||||
bool hasNextFile;
|
||||
};
|
||||
|
||||
struct VFileZip {
|
||||
struct VFile d;
|
||||
unzFile z;
|
||||
void* buffer;
|
||||
size_t fileSize;
|
||||
};
|
||||
#endif
|
||||
|
||||
static bool _vfzClose(struct VFile* vf);
|
||||
static off_t _vfzSeek(struct VFile* vf, off_t offset, int whence);
|
||||
static ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size);
|
||||
|
@ -55,6 +79,13 @@ static const char* _vdezName(struct VDirEntry* vde);
|
|||
static enum VFSType _vdezType(struct VDirEntry* vde);
|
||||
|
||||
struct VDir* VDirOpenZip(const char* path, int flags) {
|
||||
#ifndef USE_LIBZIP
|
||||
UNUSED(flags);
|
||||
unzFile z = unzOpen(path);
|
||||
if (!z) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int zflags = 0;
|
||||
if (flags & O_CREAT) {
|
||||
zflags |= ZIP_CREATE;
|
||||
|
@ -67,6 +98,7 @@ struct VDir* VDirOpenZip(const char* path, int flags) {
|
|||
if (!z) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
struct VDirZip* vd = malloc(sizeof(struct VDirZip));
|
||||
|
||||
vd->d.close = _vdzClose;
|
||||
|
@ -76,14 +108,21 @@ struct VDir* VDirOpenZip(const char* path, int flags) {
|
|||
vd->d.openDir = _vdzOpenDir;
|
||||
vd->z = z;
|
||||
|
||||
#ifndef USE_LIBZIP
|
||||
vd->hasNextFile = true;
|
||||
#endif
|
||||
|
||||
vd->dirent.d.name = _vdezName;
|
||||
vd->dirent.d.type = _vdezType;
|
||||
#ifdef USE_LIBZIP
|
||||
vd->dirent.index = -1;
|
||||
#endif
|
||||
vd->dirent.z = z;
|
||||
|
||||
return &vd->d;
|
||||
}
|
||||
|
||||
#ifdef USE_LIBZIP
|
||||
bool _vfzClose(struct VFile* vf) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
if (zip_fclose(vfz->zf) < 0) {
|
||||
|
@ -326,5 +365,212 @@ static enum VFSType _vdezType(struct VDirEntry* vde) {
|
|||
UNUSED(vdez);
|
||||
return VFS_UNKNOWN;
|
||||
}
|
||||
#else
|
||||
bool _vfzClose(struct VFile* vf) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
unzCloseCurrentFile(vfz->z);
|
||||
free(vfz->buffer);
|
||||
free(vfz);
|
||||
return true;
|
||||
}
|
||||
|
||||
off_t _vfzSeek(struct VFile* vf, off_t offset, int whence) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
|
||||
int64_t currentPos = unztell64(vfz->z);
|
||||
int64_t pos;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
pos = 0;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
pos = unztell64(vfz->z);
|
||||
break;
|
||||
case SEEK_END:
|
||||
pos = vfz->fileSize;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos < 0 || pos + offset < 0) {
|
||||
return -1;
|
||||
}
|
||||
pos += offset;
|
||||
if (currentPos > pos) {
|
||||
unzCloseCurrentFile(vfz->z);
|
||||
unzOpenCurrentFile(vfz->z);
|
||||
currentPos = 0;
|
||||
}
|
||||
while (currentPos < pos) {
|
||||
char tempBuf[1024];
|
||||
ssize_t toRead = sizeof(tempBuf);
|
||||
if (toRead > pos - currentPos) {
|
||||
toRead = pos - currentPos;
|
||||
}
|
||||
ssize_t read = vf->read(vf, tempBuf, toRead);
|
||||
if (read < toRead) {
|
||||
return -1;
|
||||
}
|
||||
currentPos += read;
|
||||
}
|
||||
|
||||
return unztell64(vfz->z);
|
||||
}
|
||||
|
||||
ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
return unzReadCurrentFile(vfz->z, buffer, size);
|
||||
}
|
||||
|
||||
ssize_t _vfzWrite(struct VFile* vf, const void* buffer, size_t size) {
|
||||
// TODO
|
||||
UNUSED(vf);
|
||||
UNUSED(buffer);
|
||||
UNUSED(size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void* _vfzMap(struct VFile* vf, size_t size, int flags) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
|
||||
// TODO
|
||||
UNUSED(flags);
|
||||
|
||||
off_t pos = vf->seek(vf, 0, SEEK_CUR);
|
||||
if (pos < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfz->buffer = anonymousMemoryMap(size);
|
||||
if (!vfz->buffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unzCloseCurrentFile(vfz->z);
|
||||
unzOpenCurrentFile(vfz->z);
|
||||
vf->read(vf, vfz->buffer, size);
|
||||
unzCloseCurrentFile(vfz->z);
|
||||
unzOpenCurrentFile(vfz->z);
|
||||
vf->seek(vf, pos, SEEK_SET);
|
||||
|
||||
return vfz->buffer;
|
||||
}
|
||||
|
||||
void _vfzUnmap(struct VFile* vf, void* memory, size_t size) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
|
||||
if (memory != vfz->buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
mappedMemoryFree(vfz->buffer, size);
|
||||
vfz->buffer = 0;
|
||||
}
|
||||
|
||||
void _vfzTruncate(struct VFile* vf, size_t size) {
|
||||
// TODO
|
||||
UNUSED(vf);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
ssize_t _vfzSize(struct VFile* vf) {
|
||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||
return vfz->fileSize;
|
||||
}
|
||||
|
||||
bool _vdzClose(struct VDir* vd) {
|
||||
struct VDirZip* vdz = (struct VDirZip*) vd;
|
||||
if (unzClose(vdz->z) < 0) {
|
||||
return false;
|
||||
}
|
||||
free(vdz);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _vdzRewind(struct VDir* vd) {
|
||||
struct VDirZip* vdz = (struct VDirZip*) vd;
|
||||
vdz->hasNextFile = unzGoToFirstFile(vdz->z) == UNZ_OK;
|
||||
}
|
||||
|
||||
struct VDirEntry* _vdzListNext(struct VDir* vd) {
|
||||
struct VDirZip* vdz = (struct VDirZip*) vd;
|
||||
if (!vdz->hasNextFile) {
|
||||
return 0;
|
||||
}
|
||||
unz_file_info64 info;
|
||||
int status = unzGetCurrentFileInfo64(vdz->z, &info, vdz->dirent.name, sizeof(vdz->dirent.name), 0, 0, 0, 0);
|
||||
if (status < 0) {
|
||||
return 0;
|
||||
}
|
||||
vdz->dirent.fileSize = info.uncompressed_size;
|
||||
if (unzGoToNextFile(vdz->z) == UNZ_END_OF_LIST_OF_FILE) {
|
||||
vdz->hasNextFile = false;
|
||||
}
|
||||
return &vdz->dirent.d;
|
||||
}
|
||||
|
||||
struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) {
|
||||
UNUSED(mode);
|
||||
struct VDirZip* vdz = (struct VDirZip*) vd;
|
||||
|
||||
if ((mode & O_ACCMODE) != O_RDONLY) {
|
||||
// minizip implementation only supports read
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unzLocateFile(vdz->z, path, 0) != UNZ_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unzOpenCurrentFile(vdz->z) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unz_file_info64 info;
|
||||
int status = unzGetCurrentFileInfo64(vdz->z, &info, 0, 0, 0, 0, 0, 0);
|
||||
if (status < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VFileZip* vfz = malloc(sizeof(struct VFileZip));
|
||||
vfz->z = vdz->z;
|
||||
vfz->buffer = 0;
|
||||
vfz->fileSize = info.uncompressed_size;
|
||||
|
||||
vfz->d.close = _vfzClose;
|
||||
vfz->d.seek = _vfzSeek;
|
||||
vfz->d.read = _vfzRead;
|
||||
vfz->d.readline = VFileReadline;
|
||||
vfz->d.write = _vfzWrite;
|
||||
vfz->d.map = _vfzMap;
|
||||
vfz->d.unmap = _vfzUnmap;
|
||||
vfz->d.truncate = _vfzTruncate;
|
||||
vfz->d.size = _vfzSize;
|
||||
vfz->d.sync = _vfzSync;
|
||||
|
||||
return &vfz->d;
|
||||
}
|
||||
|
||||
struct VDir* _vdzOpenDir(struct VDir* vd, const char* path) {
|
||||
UNUSED(vd);
|
||||
UNUSED(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _vfzSync(struct VFile* vf, const void* memory, size_t size) {
|
||||
UNUSED(vf);
|
||||
UNUSED(memory);
|
||||
UNUSED(size);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* _vdezName(struct VDirEntry* vde) {
|
||||
struct VDirEntryZip* vdez = (struct VDirEntryZip*) vde;
|
||||
return vdez->name;
|
||||
}
|
||||
|
||||
static enum VFSType _vdezType(struct VDirEntry* vde) {
|
||||
struct VDirEntryZip* vdez = (struct VDirEntryZip*) vde;
|
||||
UNUSED(vdez);
|
||||
return VFS_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue