From: notaz Date: Sun, 16 Apr 2017 21:30:30 +0000 (+0300) Subject: get rid of the silly unzip_stream X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e4a2d86a03126ffb17992b71c1aec0888cb8ce76;p=picodrive.git get rid of the silly unzip_stream ... and just use zlib's inflate. Needed for the next commit. --- diff --git a/Makefile b/Makefile index 3b5a7140..9b7e37e8 100644 --- a/Makefile +++ b/Makefile @@ -170,8 +170,7 @@ OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \ CFLAGS += -Izlib endif # unzip -OBJS += unzip/unzip.o unzip/unzip_stream.o -endif +OBJS += unzip/unzip.o include platform/common/common.mak diff --git a/pico/cart.c b/pico/cart.c index 9dce38d9..d29e96cf 100644 --- a/pico/cart.c +++ b/pico/cart.c @@ -89,6 +89,16 @@ static const char *get_ext(const char *path) return ext; } +struct zip_file { + pm_file file; + ZIP *zip; + struct zipent *entry; + z_stream stream; + unsigned char inbuf[16384]; + long start; + unsigned int pos; +}; + pm_file *pm_open(const char *path) { pm_file *file = NULL; @@ -102,10 +112,10 @@ pm_file *pm_open(const char *path) #ifndef NO_ZLIB if (strcasecmp(ext, "zip") == 0) { + struct zip_file *zfile = NULL; struct zipent *zipentry; - gzFile gzf = NULL; ZIP *zipfile; - int i; + int i, ret; zipfile = openzip(path); if (zipfile != NULL) @@ -127,25 +137,29 @@ pm_file *pm_open(const char *path) goto zip_failed; found_rom_zip: - /* try to convert to gzip stream, so we could use standard gzio functions from zlib */ - gzf = zip2gz(zipfile, zipentry); - if (gzf == NULL) goto zip_failed; - - file = calloc(1, sizeof(*file)); - if (file == NULL) goto zip_failed; - file->file = zipfile; - file->param = gzf; - file->size = zipentry->uncompressed_size; - file->type = PMT_ZIP; - strncpy(file->ext, ext, sizeof(file->ext) - 1); - return file; + zfile = calloc(1, sizeof(*zfile)); + if (zfile == NULL) + goto zip_failed; + ret = seekcompresszip(zipfile, zipentry); + if (ret != 0) + goto zip_failed; + ret = inflateInit2(&zfile->stream, -15); + if (ret != Z_OK) { + elprintf(EL_STATUS, "zip: inflateInit2 %d", ret); + goto zip_failed; + } + zfile->zip = zipfile; + zfile->entry = zipentry; + zfile->start = ftell(zipfile->fp); + zfile->file.file = zfile; + zfile->file.size = zipentry->uncompressed_size; + zfile->file.type = PMT_ZIP; + strncpy(zfile->file.ext, ext, sizeof(zfile->file.ext) - 1); + return &zfile->file; zip_failed: - if (gzf) { - gzclose(gzf); - zipfile->fp = NULL; // gzclose() closed it - } closezip(zipfile); + free(zfile); return NULL; } } @@ -249,13 +263,33 @@ size_t pm_read(void *ptr, size_t bytes, pm_file *stream) #ifndef NO_ZLIB else if (stream->type == PMT_ZIP) { - gzFile gf = stream->param; - int err; - ret = gzread(gf, ptr, bytes); - err = gzerror2(gf); - if (ret > 0 && (err == Z_DATA_ERROR || err == Z_STREAM_END)) - /* we must reset stream pointer or else next seek/read fails */ - gzrewind(gf); + struct zip_file *z = stream->file; + + if (z->entry->compression_method == 0) { + int ret = fread(ptr, 1, bytes, z->zip->fp); + z->pos += ret; + return ret; + } + + z->stream.next_out = ptr; + z->stream.avail_out = bytes; + while (z->stream.avail_out != 0) { + if (z->stream.avail_in == 0) { + z->stream.avail_in = fread(z->inbuf, 1, sizeof(z->inbuf), z->zip->fp); + if (z->stream.avail_in == 0) + break; + z->stream.next_in = z->inbuf; + } + ret = inflate(&z->stream, Z_NO_FLUSH); + if (ret == Z_STREAM_END) + break; + if (ret != Z_OK) { + elprintf(EL_STATUS, "zip: inflate: %d", ret); + return 0; + } + } + z->pos += bytes - z->stream.avail_out; + return bytes - z->stream.avail_out; } #endif else if (stream->type == PMT_CSO) @@ -336,12 +370,45 @@ int pm_seek(pm_file *stream, long offset, int whence) #ifndef NO_ZLIB else if (stream->type == PMT_ZIP) { - if (PicoMessage != NULL && offset > 6*1024*1024) { - long pos = gztell((gzFile) stream->param); - if (offset < pos || offset - pos > 6*1024*1024) - PicoMessage("Decompressing data..."); + struct zip_file *z = stream->file; + unsigned int pos = z->pos; + int ret; + + switch (whence) + { + case SEEK_CUR: pos += offset; break; + case SEEK_SET: pos = offset; break; + case SEEK_END: pos = stream->size - offset; break; + } + if (z->entry->compression_method == 0) { + ret = fseek(z->zip->fp, z->start + pos, SEEK_SET); + if (ret == 0) + return (z->pos = pos); + return -1; + } + offset = pos - z->pos; + if (pos < z->pos) { + // full decompress from the start + fseek(z->zip->fp, z->start, SEEK_SET); + z->stream.avail_in = 0; + z->stream.next_in = z->inbuf; + inflateReset(&z->stream); + z->pos = 0; + offset = pos; + } + + if (PicoMessage != NULL && offset > 4 * 1024 * 1024) + PicoMessage("Decompressing data..."); + + while (offset > 0) { + char buf[16 * 1024]; + size_t l = offset > sizeof(buf) ? sizeof(buf) : offset; + ret = pm_read(buf, l, stream); + if (ret != l) + break; + offset -= l; } - return gzseek((gzFile) stream->param, offset, whence); + return z->pos; } #endif else if (stream->type == PMT_CSO) @@ -372,10 +439,9 @@ int pm_close(pm_file *fp) #ifndef NO_ZLIB else if (fp->type == PMT_ZIP) { - ZIP *zipfile = fp->file; - gzclose((gzFile) fp->param); - zipfile->fp = NULL; // gzclose() closed it - closezip(zipfile); + struct zip_file *z = fp->file; + inflateEnd(&z->stream); + closezip(z->zip); } #endif else if (fp->type == PMT_CSO) diff --git a/unzip/unzip_stream.c b/unzip/unzip_stream.c deleted file mode 100644 index 7f3e9354..00000000 --- a/unzip/unzip_stream.c +++ /dev/null @@ -1,178 +0,0 @@ -/* seekable zip */ - -#include "unzip.h" - -#include -#include -#include - -#include "zlib/zlib.h" - - -#define errormsg(str1,def,fname) printf("%s: " #def ": " str1 "\n", fname); - - -/* from gzio.c . Be careful with binary compatibility */ -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#define ALLOC(size) malloc(size) - -int destroy OF((gz_stream *s)); - - -gzFile zip2gz(ZIP* zip, struct zipent* ent) -{ - int err; - gz_stream *s; - const char *path; - int transparent = 0; - uInt len; - - if (!zip || !ent) - return NULL; - - /* zip stuff */ - if (ent->compression_method == 0x0000) - { - /* file is not compressed, simply stored */ - - /* check if size are equal */ - if (ent->compressed_size != ent->uncompressed_size) { - errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip); - return NULL; - } - - transparent = 1; - } - else if (ent->compression_method == 0x0008) - { - /* file is compressed using "Deflate" method */ - if (ent->version_needed_to_extract > 0x14) { - errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip); - return NULL; - } - - if (ent->os_needed_to_extract != 0x00) { - errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip); - return NULL; - } - - if (ent->disk_number_start != zip->number_of_this_disk) { - errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip); - return NULL; - } - - } else { - errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip); - return NULL; - } - - /* seek to compressed data */ - if (seekcompresszip(zip,ent) != 0) { - return NULL; - } - - path = zip->zip; - - /* normal gzip init for read */ - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = transparent; - s->mode = 'r'; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = zip->fp; - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - - /* check_header(s); */ - errno = 0; - len = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - return destroy(s), (gzFile)Z_NULL; - } - - s->start = ftell(s->file) - s->stream.avail_in; - - return (gzFile)s; -} - - -int gzerror2(gzFile file) -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) - return Z_STREAM_ERROR; - - return s->z_err; -} - - diff --git a/unzip/unzip_stream.h b/unzip/unzip_stream.h deleted file mode 100644 index 59ff2faf..00000000 --- a/unzip/unzip_stream.h +++ /dev/null @@ -1,4 +0,0 @@ - -gzFile zip2gz(ZIP* zip, struct zipent* ent); -int gzerror2(gzFile file); -