static int pushresult (lua_State *L, int i, const char *filename) { if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (filename) lua_pushfstring(L, "%s: %s", filename, zzip_strerror(zzip_errno(errno))); else lua_pushfstring(L, "%s", zzip_strerror(zzip_errno(errno))); lua_pushnumber(L, zzip_errno(errno)); return 3; } }
/** * This function will read(2) data from a real/zipped file. * * the replacement for => read(2) will fill the given buffer with bytes from * the opened file. It will return the number of bytes read, so if the EOF * is encountered you will be prompted with the number of bytes actually read. * * If the file-handle is wrapping a stat'able file then it will actually just * perform a normal => read(2)-call, otherwise => zzip_file_read is called * to decompress the data stream and any error is mapped to => errno(3). */ zzip_ssize_t zzip_read(ZZIP_FILE * fp, char * buf, zzip_size_t len) { if (! fp) return 0; if (! fp->dir) { return fp->io->read(fp->fd, buf, len); } /* stat fd */ else { register zzip_ssize_t v; v = zzip_file_read(fp, buf, len); if (v == -1) { errno = zzip_errno(fp->dir->errcode); } return v; } }
/** => zzip_opendir * This function uses explicit ext and io instead of the internal * defaults, setting them to zero is equivalent to => zzip_opendir */ ZZIP_DIR * zzip_opendir_ext_io(zzip_char_t * filename, int o_modes, zzip_strings_t * ext, zzip_plugin_io_t io) { zzip_error_t e; ZZIP_DIR *dir; # ifdef ZZIP_HAVE_SYS_STAT_H struct stat st; # endif if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP)) goto try_zzip; try_real: # ifdef ZZIP_HAVE_SYS_STAT_H if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode)) { if (USE_DIRENT) { _zzip_DIR *realdir = _zzip_opendir(filename); if (realdir) { if (! (dir = (ZZIP_DIR *) calloc(1, sizeof(*dir)))) { _zzip_closedir(realdir); return 0; } else { dir->realdir = realdir; dir->realname = kdStrdup(filename); return dir; } } } return 0; } # endif /* HAVE_SYS_STAT_H */ try_zzip: dir = zzip_dir_open_ext_io(filename, &e, ext, io); if (! dir && (o_modes & ZZIP_PREFERZIP)) goto try_real; if (e) kdSetError ( zzip_errno(e) ); return dir; }
/** * This function will read(2) data from a real/zipped file. * * the replacement for => read(2) will fill the given buffer with bytes from * the opened file. It will return the number of bytes read, so if the EOF * is encountered you will be prompted with the number of bytes actually read. * * If the file-handle is wrapping a stat'able file then it will actually just * perform a normal => read(2)-call, otherwise => zzip_file_read is called * to decompress the data stream and any error is mapped to => errno(3). */ zzip_ssize_t zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len) { if (! fp) return 0; if (! fp->dir) { return fp->io->fd.read(fp->fd, buf, len); } /* stat fd */ else { register zzip_ssize_t v; v = zzip_file_read(fp, buf, len); #ifdef ZZIP_DISABLED if (v == -1) { errno = zzip_errno(fp->dir->errcode); } #endif /* ZZIP_DISABLED */ return v; } }
/** ** Generate a list of files within a specified directory ** ** @param dirname Directory to read. ** @param filter Optional xdata-filter function. ** @param flp Filelist pointer. ** ** @return Pointer to FileList struct describing Files found. */ global int ReadDataDirectory(const char* dirname,int (*filter)(char*,FileList *),FileList **flp) { #ifdef USE_ZZIPLIB ZZIP_DIR *dirp = NULL; ZZIP_DIRENT *dp; // ATTENTION: valid until end of file! #define readdir zzip_readdir #define closedir zzip_closedir int i; int entvalid; char zzbasepath[PATH_MAX]; struct stat st; char *cp; #else #ifndef _MSC_VER DIR *dirp; struct dirent *dp; #endif struct stat st; #endif #ifdef _MSC_VER struct _finddata_t fileinfo; long hFile; #endif FileList *nfl; FileList *fl = NULL; int n; int isdir = 0; // silence gcc.. char *np; char buffer[PATH_MAX]; char *filename; strcpy(buffer, dirname); n = strlen(buffer); if (!n || buffer[n - 1] != '/') { buffer[n++] = '/'; buffer[n] = 0; } np = buffer + n; n = 0; #ifdef USE_ZZIPLIB strcpy (zzbasepath, dirname); /* per each slash in filename, check if it there is a zzip around */ while ((cp = strrchr(zzbasepath, '/'))) { int fd; zzip_error_t e; *cp = '\0'; /* cut at path separator == possible zipfile basename */ fd = __my_zzip_open_zip(zzbasepath, O_RDONLY|O_BINARY); if (fd != -1) { /* found zip-file, now open it */ dirp = zzip_dir_fdopen(fd, &e); if (e) { errno = zzip_errno(e); close(fd); dirp = NULL; } break; } } if (!dirp) { int fd; zzip_error_t e; // this is tricky - we used to simply zzip_opendir(dirname) here, but // zziplib (correctly) prefers real directories over same named zipfiles // and we want it vice versa in this special case. Otherwise it would not // match the path separator backtrace above, which relies on recursive // __zip_open_dir(). __zip_open_dir() only detects zipfiles, not real dirs! fd = __my_zzip_open_zip(dirname, O_RDONLY|O_BINARY); if (fd == -1) { dirp = zzip_opendir(dirname); zzbasepath[0] = 0; } else { dirp = zzip_dir_fdopen(fd, &e); if (e) { errno = zzip_errno(e); close(fd); dirp = NULL; } else { strcpy (zzbasepath, dirname); } DebugLevel3Fn("zzbasepath `%s', dirname `%s'\n" _C_ zzbasepath _C_ dirname); } } #ifndef _MSC_VER IfDebug(if (!dirp) { DebugLevel0Fn("Dir `%s' not found\n" _C_ dirname); });
ZZIP_FILE* zzip_open_shared_io (ZZIP_FILE* stream, zzip_char_t* filename, int o_flags, int o_modes, zzip_strings_t* ext, zzip_plugin_io_t io) { if (stream && stream->dir) { if (! ext) ext = stream->dir->fileext; if (! io) io = stream->dir->io; } if (! io) io = zzip_get_default_io (); if (o_modes & (ZZIP_PREFERZIP|ZZIP_ONLYZIP)) goto try_zzip; try_real: /* prefer an existing real file */ { zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL) ? zzip_get_default_io () : io; int fd = os->fd.open(filename, o_flags); /* io->fd.open */ if (fd != -1) { #if !defined(WINDOWSPC) || defined(__MINGW32__) struct stat st; // JMW #endif ZZIP_FILE* fp = calloc (1, sizeof(ZZIP_FILE)); if (! fp) { os->fd.close(fd); return 0; } /* io->fd.close */ fp->dir = NULL; fp->fd = fd; fp->io = os; #if !defined(WINDOWSPC) || defined(__MINGW32__) if (stat(filename,&st) >=0) fp->usize = st.st_size; #else fp->usize = os->fd.filesize(fd); #endif return fp; } if (o_modes & ZZIP_PREFERZIP) { return 0; } } try_zzip: /* if the user had it in place of a normal xopen, then * we better defend this lib against illegal usage */ if (o_flags & (O_CREAT|O_WRONLY)) { errno = EINVAL; return 0; } if (o_flags & (O_RDWR)) { o_flags ^= O_RDWR; o_flags |= O_RDONLY; } /* this is just for backward compatibility -and strictly needed to * prepare ourselves for more options and more options later on... */ /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */ /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */ /* see if we can open a file that is a zip file */ { char basename[PATH_MAX]; char* p; int filename_len = strlen (filename); if (filename_len >= PATH_MAX) { #ifdef ENAMETOOLONG errno = ENAMETOOLONG; #endif return 0; } memcpy (basename, filename, filename_len+1); /* see if we can share the same zip directory */ if (stream && stream->dir && stream->dir->realname) { zzip_size_t len = strlen (stream->dir->realname); if (! memcmp (filename, stream->dir->realname, len) && ((filename[len] == '/') || (filename[len] == '\\')) && filename[len+1]) { ZZIP_FILE* fp = zzip_file_open (stream->dir, filename+len+1, o_modes); if (! fp) { errno = zzip_errno (stream->dir->errcode); } return fp; } } /* per each slash in filename, check if it there is a zzip around */ while ((p = strrchr (basename, '/')) || (p = strrchr (basename, '\\'))) { zzip_error_t e = 0; ZZIP_DIR* dir; ZZIP_FILE* fp; int fd; *p = '\0'; /* cut at path separator == possible zipfile basename */ fd = __zzip_try_open (basename, o_flags|O_RDONLY|O_BINARY, ext, io); if (fd == -1) { continue; } /* found: */ /* found zip-file, now try to parse it */ dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io); if (e) { errno = zzip_errno(e); io->fd.close(fd); return 0; } /* (p - basename) is the lenghtof zzip_dir part of the filename */ fp = zzip_file_open(dir, filename + (p - basename) +1, o_modes); if (! fp) { errno = zzip_errno(dir->errcode); } else { if (! dir->realname) dir->realname = strdup (basename); } zzip_dir_close(dir); /* note: since (fp) is attached that (dir) will survive */ /* but (dir) is implicitly closed on next zzip_close(fp) */ return fp; } /*again*/ if (o_modes & ZZIP_PREFERZIP) goto try_real; errno = ENOENT; return 0; } }
/** * open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since * we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk * this is the best choice to unpack multiple files. * * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k * memchunk here... just to be safe. */ ZZIP_FILE * zzip_file_open(ZZIP_DIR * dir, zzip_char_t* name, int o_mode) { zzip_error_t err = 0; struct zzip_file * fp = 0; struct zzip_dir_hdr * hdr = dir->hdr0; int (*cmp)(zzip_char_t*, zzip_char_t*); cmp = (o_mode & ZZIP_CASELESS)? dirsep_casecmp: strcmp; if (! dir || !dir->fd || dir->fd == -1 ) return 0; if (o_mode & ZZIP_NOPATHS) { register zzip_char_t* n = dirsep_strrchr(name, '/'); if (n) name = n + 1; } if (hdr) while (1) { register zzip_char_t* hdr_name = hdr->d_name; if (o_mode & ZZIP_NOPATHS) { register zzip_char_t* n = dirsep_strrchr(hdr_name, '/'); if (n) hdr_name = n + 1; } HINT4("name='%s', compr=%d, size=%d\n", hdr->d_name, hdr->d_compr, hdr->d_usize); if (!cmp(hdr_name, name)) { switch (hdr->d_compr) { case 0: /* store */ case 8: /* inflate */ break; default: { err = ZZIP_UNSUPP_COMPR; goto error; } } if (dir->cache.fp) { fp = dir->cache.fp; dir->cache.fp = NULL; /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */ }else { if (! (fp = (ZZIP_FILE *)calloc(1, sizeof(*fp)))) { err = ZZIP_OUTOFMEM; goto error; } } fp->dir = dir; fp->io = dir->io; dir->refcount++; if (dir->cache.buf32k) { fp->buf32k = dir->cache.buf32k; dir->cache.buf32k = NULL; } else { if (! (fp->buf32k = (char *)malloc(ZZIP_32K))) { err = ZZIP_OUTOFMEM; goto error; } } /* * In order to support simultaneous open files in one zip archive * we'll fix the fd offset when opening new file/changing which * file to read... */ if (zzip_file_saveoffset(dir->currentfp) < 0) { err = ZZIP_DIR_SEEK; goto error; } fp->offset = hdr->d_off; dir->currentfp = fp; if (dir->io->seeks(dir->fd, hdr->d_off, SEEK_SET) < 0) { err = ZZIP_DIR_SEEK; goto error; } { /* skip local header - should test tons of other info, * but trust that those are correct */ zzip_ssize_t dataoff; struct zzip_file_header * p = (void*) fp->buf32k; dataoff = dir->io->read(dir->fd, (void*)p, sizeof(*p)); if (dataoff < (zzip_ssize_t)sizeof(*p)) { err = ZZIP_DIR_READ; goto error; } if (! ZZIP_FILE_HEADER_CHECKMAGIC(p)) /* PK\3\4 */ { err = ZZIP_CORRUPTED; goto error; } dataoff = ZZIP_GET16(p->z_namlen) + ZZIP_GET16(p->z_extras); if (dir->io->seeks(dir->fd, dataoff, SEEK_CUR) < 0) { err = ZZIP_DIR_SEEK; goto error; } fp->dataoffset = dir->io->tells(dir->fd); fp->usize = hdr->d_usize; fp->csize = hdr->d_csize; } err = zzip_inflate_init (fp, hdr); if (err) { goto error; } return fp; }else { if (hdr->d_reclen == 0) break; hdr = (struct zzip_dir_hdr *)((char *)hdr + hdr->d_reclen); }/*cmp name*/ }/*forever*/ dir->errcode = ZZIP_ENOENT; zzip_errno(ZZIP_ENOENT); return NULL; error: if (fp) zzip_file_close(fp); dir->errcode = err; zzip_errno(err); return NULL; }