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_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_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_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_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_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")
|
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 FEATURES LIBZIP)
|
||||||
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
|
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2")
|
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()
|
endif()
|
||||||
|
|
||||||
if (USE_LZMA)
|
if (USE_LZMA)
|
||||||
|
@ -602,7 +606,6 @@ message(STATUS " GDB stub: ${USE_GDB_STUB}")
|
||||||
message(STATUS " Video recording: ${USE_FFMPEG}")
|
message(STATUS " Video recording: ${USE_FFMPEG}")
|
||||||
message(STATUS " GIF recording: ${USE_MAGICK}")
|
message(STATUS " GIF recording: ${USE_MAGICK}")
|
||||||
message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}")
|
message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}")
|
||||||
message(STATUS " ZIP support: ${USE_LIBZIP}")
|
|
||||||
message(STATUS " 7-Zip support: ${USE_LZMA}")
|
message(STATUS " 7-Zip support: ${USE_LZMA}")
|
||||||
message(STATUS " Better audio resampling: ${USE_BLIP}")
|
message(STATUS " Better audio resampling: ${USE_BLIP}")
|
||||||
message(STATUS "Frontend summary:")
|
message(STATUS "Frontend summary:")
|
||||||
|
|
|
@ -98,7 +98,7 @@ struct VFile* VFileOpen(const char* path, int flags) {
|
||||||
|
|
||||||
struct VDir* VDirOpenArchive(const char* path) {
|
struct VDir* VDirOpenArchive(const char* path) {
|
||||||
struct VDir* dir = 0;
|
struct VDir* dir = 0;
|
||||||
#if USE_LIBZIP
|
#if defined(USE_LIBZIP) || defined(USE_ZLIB)
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
dir = VDirOpenZip(path, 0);
|
dir = VDirOpenZip(path, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct VFile* VFileFromFILE(FILE* file);
|
||||||
struct VDir* VDirOpen(const char* path);
|
struct VDir* VDirOpen(const char* path);
|
||||||
struct VDir* VDirOpenArchive(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);
|
struct VDir* VDirOpenZip(const char* path, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,6 @@
|
||||||
#ifdef USE_LIBZIP
|
#ifdef USE_LIBZIP
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BLOCK_SIZE = 1024
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VDirEntryZip {
|
struct VDirEntryZip {
|
||||||
struct VDirEntry d;
|
struct VDirEntry d;
|
||||||
struct zip* z;
|
struct zip* z;
|
||||||
|
@ -35,6 +30,35 @@ struct VFileZip {
|
||||||
size_t fileSize;
|
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 bool _vfzClose(struct VFile* vf);
|
||||||
static off_t _vfzSeek(struct VFile* vf, off_t offset, int whence);
|
static off_t _vfzSeek(struct VFile* vf, off_t offset, int whence);
|
||||||
static ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size);
|
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);
|
static enum VFSType _vdezType(struct VDirEntry* vde);
|
||||||
|
|
||||||
struct VDir* VDirOpenZip(const char* path, int flags) {
|
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;
|
int zflags = 0;
|
||||||
if (flags & O_CREAT) {
|
if (flags & O_CREAT) {
|
||||||
zflags |= ZIP_CREATE;
|
zflags |= ZIP_CREATE;
|
||||||
|
@ -67,6 +98,7 @@ struct VDir* VDirOpenZip(const char* path, int flags) {
|
||||||
if (!z) {
|
if (!z) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
struct VDirZip* vd = malloc(sizeof(struct VDirZip));
|
struct VDirZip* vd = malloc(sizeof(struct VDirZip));
|
||||||
|
|
||||||
vd->d.close = _vdzClose;
|
vd->d.close = _vdzClose;
|
||||||
|
@ -76,14 +108,21 @@ struct VDir* VDirOpenZip(const char* path, int flags) {
|
||||||
vd->d.openDir = _vdzOpenDir;
|
vd->d.openDir = _vdzOpenDir;
|
||||||
vd->z = z;
|
vd->z = z;
|
||||||
|
|
||||||
|
#ifndef USE_LIBZIP
|
||||||
|
vd->hasNextFile = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
vd->dirent.d.name = _vdezName;
|
vd->dirent.d.name = _vdezName;
|
||||||
vd->dirent.d.type = _vdezType;
|
vd->dirent.d.type = _vdezType;
|
||||||
|
#ifdef USE_LIBZIP
|
||||||
vd->dirent.index = -1;
|
vd->dirent.index = -1;
|
||||||
|
#endif
|
||||||
vd->dirent.z = z;
|
vd->dirent.z = z;
|
||||||
|
|
||||||
return &vd->d;
|
return &vd->d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_LIBZIP
|
||||||
bool _vfzClose(struct VFile* vf) {
|
bool _vfzClose(struct VFile* vf) {
|
||||||
struct VFileZip* vfz = (struct VFileZip*) vf;
|
struct VFileZip* vfz = (struct VFileZip*) vf;
|
||||||
if (zip_fclose(vfz->zf) < 0) {
|
if (zip_fclose(vfz->zf) < 0) {
|
||||||
|
@ -326,5 +365,212 @@ static enum VFSType _vdezType(struct VDirEntry* vde) {
|
||||||
UNUSED(vdez);
|
UNUSED(vdez);
|
||||||
return VFS_UNKNOWN;
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue