VFS: Support using minizip for zip

This commit is contained in:
Jeffrey Pfau 2015-12-29 04:32:25 -05:00
parent dd91b689a2
commit 96bc0be963
4 changed files with 258 additions and 9 deletions

View File

@ -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:")

View File

@ -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);
}

View File

@ -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

View File

@ -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