4 * Guido Draheim <guidod@gmx.de>
5 * Tomi Ollila <Tomi.Ollila@iki.fi>
7 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
9 * use under the restrictions of the
10 * Lesser GNU General Public License
11 * or alternatively the restrictions
12 * of the Mozilla Public License 1.1
15 #include <zzip/lib.h> /* exported... */
16 #include <zzip/file.h>
24 #include <zzip/format.h>
25 #include <zzip/fetch.h>
26 #include <zzip/__debug.h>
29 # if defined ZZIP_HAVE_IO_H
30 # include <io.h> /* tell */
32 # define tell(fd) lseek(fd,0,SEEK_CUR)
35 #define tells(fd) seeks(fd,0,SEEK_CUR)
39 * the direct function of => zzip_close(fp). it will cleanup the
40 * inflate-portion of => zlib and free the structure given.
42 * it is called quite from the error-cleanup parts
43 * of the various => _open functions.
45 * the .refcount is decreased and if zero the fp->dir is closed just as well.
48 zzip_file_close(ZZIP_FILE * fp)
51 ZZIP_DIR *dir = fp->dir;
54 inflateEnd(&fp->d_stream); /* inflateEnd() can be called many times */
56 if (dir->cache.locked == NULL)
57 dir->cache.locked = &self;
61 if (dir->cache.locked == &self && dir->cache.buf32k == NULL)
62 dir->cache.buf32k = fp->buf32k;
67 if (dir->currentfp == fp)
68 dir->currentfp = NULL;
71 /* ease to notice possible dangling reference errors */
72 memset(fp, 0, sizeof(*fp));
74 if (dir->cache.locked == &self && dir->cache.fp == NULL)
79 if (dir->cache.locked == &self)
80 dir->cache.locked = NULL;
83 return zzip_dir_close(dir);
90 zzip_file_saveoffset(ZZIP_FILE * fp)
95 zzip_off_t off = fp->io->fd.seeks(fd, 0, SEEK_CUR);
105 # ifndef ZZIP_CHECK_BACKSLASH_DIRSEPARATOR /* NOTE: also default */
106 # define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 0 /* to "NO" on win32 ! */
109 # if ! defined strcasecmp && ! defined ZZIP_HAVE_STRCASECMP
110 # define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 1
113 #if ! ZZIP_CHECK_BACKSLASH_DIRSEPARATOR+0
114 #define dirsep_strrchr(N,C) strrchr(N,C)
115 #define dirsep_casecmp strcasecmp
117 #define dirsep_strrchr(N,C) _dirsep_strrchr(N)
118 #define dirsep_casecmp _dirsep_casecmp
120 _dirsep_strrchr(zzip_char_t * name)
122 char *n = strrchr(name, '/');
123 char *m = strrchr(name, '\\');
130 _dirsep_casecmp(zzip_char_t * s1, zzip_char_t * s2)
132 /* ASCII tolower - including mapping of backslash in normal slash */
133 static const char mapping[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
138 c1 = (int) (unsigned char) *s1;
139 c2 = (int) (unsigned char) *s2;
140 if ((c1 & 0xE0) == 0x40)
141 c1 = mapping[c1 & 0x1f];
142 if ((c2 & 0xE0) == 0x40)
143 c2 = mapping[c2 & 0x1f];
150 return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
154 static int zzip_inflate_init(ZZIP_FILE *, struct zzip_dir_hdr *);
157 * open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since
158 * we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
159 * this is the best choice to unpack multiple files.
161 * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
162 * memchunk here... just to be safe.
164 * On error it returns null and sets errcode in the ZZIP_DIR.
167 zzip_file_open(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
170 zzip_error_t err = 0;
171 struct zzip_file *fp = 0;
172 struct zzip_dir_hdr *hdr = dir->hdr0;
173 int (*cmp) (zzip_char_t *, zzip_char_t *);
175 cmp = (o_mode & ZZIP_CASELESS) ? dirsep_casecmp : strcmp;
179 if (! dir->fd || dir->fd == -1)
180 { dir->errcode = EBADF; return NULL; }
182 { dir->errcode = ENOENT; return NULL; }
184 if (o_mode & ZZIP_NOPATHS)
186 register zzip_char_t *n = dirsep_strrchr(name, '/');
194 register zzip_char_t *hdr_name = hdr->d_name;
196 if (o_mode & ZZIP_NOPATHS)
198 register zzip_char_t *n = dirsep_strrchr(hdr_name, '/');
204 HINT4("name='%s', compr=%d, size=%d\n",
205 hdr->d_name, hdr->d_compr, hdr->d_usize);
207 if (! cmp(hdr_name, name))
209 switch (hdr->d_compr)
212 case 8: /* inflate */
215 { err = ZZIP_UNSUPP_COMPR; goto error; }
218 if (dir->cache.locked == NULL)
219 dir->cache.locked = &self;
221 if (dir->cache.locked == &self && dir->cache.fp)
224 dir->cache.fp = NULL;
225 /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
228 if (! (fp = (ZZIP_FILE *) calloc(1, sizeof(*fp))))
229 { err = ZZIP_OUTOFMEM; goto error; }
236 if (dir->cache.locked == &self && dir->cache.buf32k)
238 fp->buf32k = dir->cache.buf32k;
239 dir->cache.buf32k = NULL;
242 if (! (fp->buf32k = (char *) malloc(ZZIP_32K)))
243 { err = ZZIP_OUTOFMEM; goto error; }
246 if (dir->cache.locked == &self)
247 dir->cache.locked = NULL;
249 * In order to support simultaneous open files in one zip archive
250 * we'll fix the fd offset when opening new file/changing which
254 if (zzip_file_saveoffset(dir->currentfp) < 0)
255 { err = ZZIP_DIR_SEEK; goto error; }
257 fp->offset = hdr->d_off;
260 if (dir->io->fd.seeks(dir->fd, hdr->d_off, SEEK_SET) < 0)
261 { err = ZZIP_DIR_SEEK; goto error; }
263 { /* skip local header - should test tons of other info,
264 * but trust that those are correct */
265 zzip_ssize_t dataoff;
266 struct zzip_file_header *p = (void *) fp->buf32k;
268 dataoff = dir->io->fd.read(dir->fd, (void *) p, sizeof(*p));
269 if (dataoff < (zzip_ssize_t) sizeof(*p))
270 { err = ZZIP_DIR_READ; goto error; }
271 if (! zzip_file_header_check_magic(p)) /* PK\3\4 */
272 { err = ZZIP_CORRUPTED; goto error; }
274 dataoff = zzip_file_header_sizeof_tail(p);
276 if (dir->io->fd.seeks(dir->fd, dataoff, SEEK_CUR) < 0)
277 { err = ZZIP_DIR_SEEK; goto error; }
279 fp->dataoffset = dir->io->fd.tells(dir->fd);
280 fp->usize = hdr->d_usize;
281 fp->csize = hdr->d_csize;
284 err = zzip_inflate_init(fp, hdr);
291 if (hdr->d_reclen == 0)
293 hdr = (struct zzip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
296 dir->errcode = ZZIP_ENOENT;
306 * call => inflateInit and setup fp's iterator variables,
307 * used by lowlevel => _open functions.
310 zzip_inflate_init(ZZIP_FILE * fp, struct zzip_dir_hdr *hdr)
314 fp->method = hdr->d_compr;
315 fp->restlen = hdr->d_usize;
319 memset(&fp->d_stream, 0, sizeof(fp->d_stream));
321 err = inflateInit2(&fp->d_stream, -MAX_WBITS);
325 fp->crestlen = hdr->d_csize;
335 * This function closes the given ZZIP_FILE handle.
337 * If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd
338 * that is being closed and the otherwise empty ZZIP_FILE gets freed.
341 zzip_fclose(ZZIP_FILE * fp)
346 { int r = fp->io->fd.close(fp->fd); free(fp); return r; } /* stat fd */
348 return zzip_file_close(fp);
354 zzip_close(ZZIP_FILE * fp)
356 return zzip_fclose(fp);
360 * This functions read data from zip-contained file.
362 * It works like => read(2) and will fill the given buffer with bytes from
363 * the opened file. It will return the number of bytes read, so if the => EOF
364 * is encountered you will be prompted with the number of bytes actually read.
366 * This is the routines that needs the => buf32k buffer, and it would have
367 * need for much more polishing but it does already work quite well.
369 * Note: the 32K buffer is rather big. The original inflate-algorithm
370 * required just that but the latest zlib would work just fine with
374 zzip_file_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
380 if (! fp || ! fp->dir)
384 l = fp->restlen > len ? len : fp->restlen;
385 if (fp->restlen == 0)
389 * If this is other handle than previous, save current seek pointer
390 * and read the file position of `this' handle.
392 if (dir->currentfp != fp)
394 if (zzip_file_saveoffset(dir->currentfp) < 0
395 || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
396 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
398 { dir->currentfp = fp; }
401 /* if more methods is to be supported, change this to `switch ()' */
402 if (fp->method) /* method != 0 == 8, inflate */
404 fp->d_stream.avail_out = l;
405 fp->d_stream.next_out = (unsigned char *) buf;
410 zzip_size_t startlen;
412 if (fp->crestlen > 0 && fp->d_stream.avail_in == 0)
414 zzip_size_t cl = (fp->crestlen < ZZIP_32K ?
415 fp->crestlen : ZZIP_32K);
416 /* zzip_size_t cl = fp->crestlen > 128 ? 128 : fp->crestlen; */
418 zzip_ssize_t i = fp->io->fd.read(dir->fd, fp->buf32k, cl);
422 dir->errcode = ZZIP_DIR_READ; /* or ZZIP_DIR_READ_EOF ? */
426 fp->d_stream.avail_in = i;
427 fp->d_stream.next_in = (unsigned char *) fp->buf32k;
430 startlen = fp->d_stream.total_out;
431 err = inflate(&fp->d_stream, Z_NO_FLUSH);
433 if (err == Z_STREAM_END)
435 else if (err == Z_OK)
436 { fp->restlen -= (fp->d_stream.total_out - startlen); }
438 { dir->errcode = err; return -1; }
440 while (fp->restlen && fp->d_stream.avail_out);
442 return l - fp->d_stream.avail_out;
444 { /* method == 0 -- unstore */
445 rv = fp->io->fd.read(dir->fd, buf, l);
447 { fp->restlen-= rv; }
449 { dir->errcode = ZZIP_DIR_READ; }
455 * This function will read(2) data from a real/zipped file.
457 * the replacement for => read(2) will fill the given buffer with bytes from
458 * the opened file. It will return the number of bytes read, so if the EOF
459 * is encountered you will be prompted with the number of bytes actually read.
461 * If the file-handle is wrapping a stat'able file then it will actually just
462 * perform a normal => read(2)-call, otherwise => zzip_file_read is called
463 * to decompress the data stream and any error is mapped to => errno(3).
466 zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
471 { return fp->io->fd.read(fp->fd, buf, len); } /* stat fd */
474 register zzip_ssize_t v;
476 v = zzip_file_read(fp, buf, len);
478 { errno = zzip_errno(fp->dir->errcode); }
486 zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE * file)
490 return zzip_read(file, ptr, size * nmemb) / size;
494 #define ZZIP_WRONLY O_WRONLY
495 #define ZZIP_EXCL O_EXCL
498 #define ZZIP_SYNC O_SYNC
503 #if defined O_NONBLOCK
504 #define ZZIP_NONBLOCK O_NONBLOCK
505 #elif defined O_NDELAY
506 #define ZZIP_NOCTTY O_NDELAY
508 #define ZZIP_NOCTTY 0
511 /* ------------------------------------------------------------------- */
514 * This function will => fopen(3) a real/zipped file.
516 * It has some magic functionality builtin - it will first try to open
517 * the given <em>filename</em> as a normal file. If it does not
518 * exist, the given path to the filename (if any) is split into
519 * its directory-part and the file-part. A ".zip" extension is
520 * then added to the directory-part to create the name of a
521 * zip-archive. That zip-archive (if it exists) is being searched
522 * for the file-part, and if found a zzip-handle is returned.
524 * Note that if the file is found in the normal fs-directory the
525 * returned structure is mostly empty and the => zzip_read call will
526 * use the libc => read to obtain data. Otherwise a => zzip_file_open
527 * is performed and any error mapped to => errno(3).
529 * unlike the posix-wrapper => zzip_open the mode-argument is
530 * a string which allows for more freedom to support the extra
531 * zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
532 * Currently, this => zzip_fopen call will convert the following
533 * characters in the mode-string into their corrsponding mode-bits:
534 * * <code> "r" : O_RDONLY : </code> read-only
535 * * <code> "b" : O_BINARY : </code> binary (win32 specific)
536 * * <code> "f" : O_NOCTTY : </code> no char device (unix)
537 * * <code> "i" : ZZIP_CASELESS : </code> inside zip file
538 * * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
539 * all other modes will be ignored for zip-contained entries
540 * but they are transferred for compatibility and portability,
541 * including these extra sugar bits:
542 * * <code> "x" : O_EXCL :</code> fail if file did exist
543 * * <code> "s" : O_SYNC :</code> synchronized access
544 * * <code> "n" : O_NONBLOCK :</code> nonblocking access
545 * * <code> "z#" : compression level :</code> for zlib
546 * * <code> "g#" : group access :</code> unix access bits
547 * * <code> "u#" : owner access :</code> unix access bits
548 * * <code> "o#" : world access :</code> unix access bits
549 * ... the access bits are in traditional unix bit format
550 * with 7 = read/write/execute, 6 = read/write, 4 = read-only.
552 * The default access mode is 0664, and the compression level
553 * is ignored since the lib can not yet write zip files, otherwise
554 * it would be the initialisation value for the zlib deflateInit
555 * where 0 = no-compression, 1 = best-speed, 9 = best-compression.
557 * This function returns a new zzip-handle (use => zzip_close to return
558 * it). On error this function will return null setting => errno(3).
561 zzip_fopen(zzip_char_t * filename, zzip_char_t * mode)
563 return zzip_freopen(filename, mode, 0);
568 * This function receives an additional argument pointing to
569 * a ZZIP_FILE* being already in use. If this extra argument is
570 * null then this function is identical with calling => zzip_fopen
572 * Per default, the old file stream is closed and only the internal
573 * structures associated with it are kept. These internal structures
574 * may be reused for the return value, and this is a lot quicker when
575 * the filename matches a zipped file that is incidently in the very
576 * same zip arch as the old filename wrapped in the stream struct.
578 * That's simply because the zip arch's central directory does not
579 * need to be read again. As an extension for this function, if the
580 * mode-string contains a "q" then the old stream is not closed but
581 * left untouched, instead it is only given as a hint that a new
582 * file handle may share/copy the zip arch structures of the old file
583 * handle if that is possible, i.e when they are in the same zip arch.
585 * This function returns a new zzip-handle (use => zzip_close to return
586 * it). On error this function will return null setting => errno(3).
589 zzip_freopen(zzip_char_t * filename, zzip_char_t * mode, ZZIP_FILE * stream)
607 # define O_NONBLOCK 0
610 for (; *mode; mode++)
615 case '0': case '1': case '2': case '3': case '4':
616 case '5': case '6': case '7': case '8': case '9':
617 continue; /* ignore if not attached to other info */
618 case 'r': o_flags |= mode[1] == '+' ? O_RDWR : O_RDONLY; break;
619 case 'w': o_flags |= mode[1] == '+' ? O_RDWR : O_WRONLY;
620 o_flags |= O_TRUNC; break;
621 case 'b': o_flags |= O_BINARY; break;
622 case 'f': o_flags |= O_NOCTTY; break;
623 case 'i': o_modes |= ZZIP_CASELESS; break;
624 case '*': o_modes |= ZZIP_NOPATHS; break;
625 case 'x': o_flags |= O_EXCL; break;
626 case 's': o_flags |= O_SYNC; break;
627 case 'n': o_flags |= O_NONBLOCK; break;
628 case 'o': o_modes &=~ 07;
629 o_modes |= ((mode[1] - '0')) & 07; continue;
630 case 'g': o_modes &=~ 070;
631 o_modes |= ((mode[1] - '0') << 3) & 070; continue;
632 case 'u': o_modes &=~ 0700;
633 o_modes |= ((mode[1] - '0') << 6) & 0700; continue;
634 case 'q': o_modes |= ZZIP_FACTORY; break;
635 case 'z': /* compression level */
636 continue; /* currently ignored, just for write mode */
643 zzip_open_shared_io(stream, filename, o_flags, o_modes, 0, 0);
645 if (! (o_modes & ZZIP_FACTORY) && stream)
646 zzip_file_close(stream);
653 * This function will => open(2) a real/zipped file
655 * It has some magic functionality builtin - it will first try to open
656 * the given <em>filename</em> as a normal file. If it does not
657 * exist, the given path to the filename (if any) is split into
658 * its directory-part and the file-part. A ".zip" extension is
659 * then added to the directory-part to create the name of a
660 * zip-archive. That zip-archive (if it exists) is being searched
661 * for the file-part, and if found a zzip-handle is returned.
663 * Note that if the file is found in the normal fs-directory the
664 * returned structure is mostly empty and the => zzip_read call will
665 * use the libc => read to obtain data. Otherwise a => zzip_file_open
666 * is performed and any error mapped to => errno(3).
668 * There was a possibility to transfer zziplib-specific openmodes
669 * through o_flags but you should please not use them anymore and
670 * look into => zzip_open_ext_io to submit them down. This function
671 * is shallow in that it just extracts the zzipflags and calls
672 * * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
673 * you must stop using this extra functionality (not well known anyway)
674 * since zzip_open might be later usable to open files for writing
675 * in which case the _EXTRAFLAGS will get in conflict.
677 * compare with => open(2) and => zzip_fopen
680 zzip_open(zzip_char_t * filename, int o_flags)
682 /* backward compatibility */
685 if (o_flags & ZZIP_CASEINSENSITIVE)
686 { o_flags ^= ZZIP_CASEINSENSITIVE; o_modes |= ZZIP_CASELESS; }
687 if (o_flags & ZZIP_IGNOREPATH)
688 { o_flags ^= ZZIP_IGNOREPATH; o_modes |= ZZIP_NOPATHS; }
689 return zzip_open_ext_io(filename, o_flags, o_modes, 0, 0);
692 /* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
693 #if ZZIP_SIZEOF_INT+0 == 2
699 * This function uses explicit ext and io instead of the internal
700 * defaults, setting them to zero is equivalent to => zzip_open
702 * note that the two flag types have been split into an o_flags
703 * (for fcntl-like openflags) and o_modes where the latter shall
704 * carry the zzip_flags and possibly accessmodes for unix filesystems.
705 * Since this version of zziplib can not write zipfiles, it is not
706 * yet used for anything else than zzip-specific modeflags.
708 * This function returns a new zzip-handle (use => zzip_close to return
709 * it). On error this function will return null setting => errno(3).
712 zzip_open_ext_io(zzip_char_t * filename, int o_flags, int o_modes,
713 zzip_strings_t * ext, zzip_plugin_io_t io)
715 return zzip_open_shared_io(0, filename, o_flags, o_modes, ext, io);
720 * This function takes an extra stream argument - if a handle has been
721 * then ext/io can be left null and the new stream handle will pick up
722 * the ext/io. This should be used only in specific environment however
723 * since => zzip_file_real does not store any ext-sequence.
725 * The benefit for this function comes in when the old file handle
726 * was openened from a file within a zip archive. When the new file
727 * is in the same zip archive then the internal zzip_dir structures
728 * will be shared. It is even quicker, as no check needs to be done
729 * anymore trying to guess the zip archive place in the filesystem,
730 * here we just check whether the zip archive's filepath is a prefix
731 * part of the filename to be opened.
733 * Note that this function is also used by => zzip_freopen that
734 * will unshare the old handle, thereby possibly closing the handle.
736 * This function returns a new zzip-handle (use => zzip_close to return
737 * it). On error this function will return null setting => errno(3).
740 zzip_open_shared_io(ZZIP_FILE * stream,
741 zzip_char_t * filename, int o_flags, int o_modes,
742 zzip_strings_t * ext, zzip_plugin_io_t io)
744 if (stream && stream->dir)
747 ext = stream->dir->fileext;
749 io = stream->dir->io;
752 io = zzip_get_default_io();
754 if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
757 /* prefer an existing real file */
759 zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL)
760 ? zzip_get_default_io() : io;
761 int fd = os->fd.open(filename, o_flags); /* io->fd.open */
765 ZZIP_FILE *fp = calloc(1, sizeof(ZZIP_FILE));
768 { os->fd.close(fd); return 0; } /* io->fd.close */
774 if (o_modes & ZZIP_PREFERZIP)
779 /* if the user had it in place of a normal xopen, then
780 * we better defend this lib against illegal usage */
781 if (o_flags & (O_CREAT | O_WRONLY))
782 { errno = EINVAL; return 0; }
783 if (o_flags & (O_RDWR))
784 { o_flags ^= O_RDWR; o_flags |= O_RDONLY; }
786 /* this is just for backward compatibility -and strictly needed to
787 * prepare ourselves for more options and more options later on... */
788 /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
789 /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */
791 /* see if we can open a file that is a zip file */
793 char basename[PATH_MAX];
795 int filename_len = strlen(filename);
797 if (filename_len >= PATH_MAX)
798 { errno = ENAMETOOLONG; return 0; }
799 memcpy(basename, filename, filename_len + 1);
801 /* see if we can share the same zip directory */
802 if (stream && stream->dir && stream->dir->realname)
804 zzip_size_t len = strlen(stream->dir->realname);
806 if (! memcmp(filename, stream->dir->realname, len) &&
807 filename[len] == '/' && filename[len + 1])
810 zzip_file_open(stream->dir, filename + len + 1, o_modes);
812 { errno = zzip_errno (stream->dir->errcode); }
817 /* per each slash in filename, check if it there is a zzip around */
818 while ((p = strrchr(basename, '/')))
825 *p = '\0'; /* cut at path separator == possible zipfile basename */
826 fd = __zzip_try_open(basename, o_flags | O_RDONLY | O_BINARY, ext,
832 /* found zip-file, now try to parse it */
833 dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io);
835 { errno = zzip_errno(e); io->fd.close(fd); return 0; }
837 /* (p - basename) is the lenghtof zzip_dir part of the filename */
838 fp = zzip_file_open(dir, filename + (p - basename) + 1, o_modes);
840 { errno = zzip_errno(dir->errcode); }
842 { if (! dir->realname) dir->realname = strdup (basename); }
845 /* note: since (fp) is attached that (dir) will survive */
846 /* but (dir) is implicitly closed on next zzip_close(fp) */
851 if (o_modes & ZZIP_PREFERZIP)
854 { errno = ENOENT; return 0; }
858 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
859 #undef zzip_open_shared_io /* zzip_open_shared_io64 */
860 #undef zzip_open_ext_io /* zzip_open_ext_io64 */
861 #undef zzip_opendir_ext_io /* zzip_opendir_ext_io64 */
864 ZZIP_FILE * zzip_open_shared_io(ZZIP_FILE * stream,
865 zzip_char_t * name, int o_flags,
866 int o_modes, zzip_strings_t * ext,
867 zzip_plugin_io_t io);
868 _zzip_export ZZIP_FILE *zzip_open_ext_io(zzip_char_t * name, int o_flags,
869 int o_modes, zzip_strings_t * ext,
870 zzip_plugin_io_t io);
871 _zzip_export ZZIP_DIR *zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
872 zzip_strings_t * ext,
873 zzip_plugin_io_t io);
875 /* DLL compatibility layer - so that 32bit code can link with this lib too */
878 ZZIP_FILE * zzip_open_shared_io(ZZIP_FILE * stream,
879 zzip_char_t * name, int o_flags,
880 int o_modes, zzip_strings_t * ext,
884 return zzip_open_shared_io64(stream, name, o_flags, o_modes, ext, io);
890 ZZIP_FILE * zzip_open_ext_io(zzip_char_t * name, int o_flags, int o_modes,
891 zzip_strings_t * ext, zzip_plugin_io_t io)
894 return zzip_open_ext_io64(name, o_flags, o_modes, ext, io);
900 ZZIP_DIR * zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
901 zzip_strings_t * ext, zzip_plugin_io_t io)
904 return zzip_opendir_ext_io64(name, o_modes, ext, io);
906 { errno = EOVERFLOW; return NULL; }
909 #endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
911 /* ------------------------------------------------------------------- */
914 * This function will rewind a real/zipped file.
916 * It seeks to the beginning of this file's data in the zip,
917 * or the beginning of the file for a stat'fd.
920 zzip_rewind(ZZIP_FILE * fp)
930 fp->io->fd.seeks(fp->fd, 0, SEEK_SET);
936 * If this is other handle than previous, save current seek pointer
938 if (dir->currentfp != fp)
940 if (zzip_file_saveoffset(dir->currentfp) < 0)
941 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
943 { dir->currentfp = fp; }
946 /* seek to beginning of this file */
947 if (fp->io->fd.seeks(dir->fd, fp->dataoffset, SEEK_SET) < 0)
950 /* reset the inflate init stuff */
951 fp->restlen = fp->usize;
952 fp->offset = fp->dataoffset;
955 { /* method == 8, deflate */
956 err = inflateReset(&fp->d_stream);
960 /* start over at next inflate with a fresh read() */
961 fp->d_stream.avail_in = 0;
962 fp->crestlen = fp->csize;
974 * This function will perform a => lseek(2) operation on a real/zipped file
976 * It will try to seek to the offset specified by offset, relative to whence,
977 * which is one of SEEK_SET, SEEK_CUR or SEEK_END.
979 * If the file-handle is wrapping a stat'able file then it will actually just
980 * perform a normal => lseek(2)-call. Otherwise the relative offset
981 * is calculated, negative offsets are transformed into positive ones
982 * by rewinding the file, and then data is read until the offset is
983 * reached. This can make the function terribly slow, but this is
984 * how gzio implements it, so I'm not sure there is a better way
985 * without using the internals of the algorithm.
988 zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence)
990 zzip_off_t cur_pos, rel_ofs, read_size, ofs;
998 return fp->io->fd.seeks(fp->fd, offset, whence);
1001 cur_pos = zzip_tell(fp);
1003 /* calculate relative offset */
1006 case SEEK_SET: /* from beginning */
1007 rel_ofs = offset - cur_pos;
1009 case SEEK_CUR: /* from current */
1012 case SEEK_END: /* from end */
1013 rel_ofs = fp->usize + offset - cur_pos;
1015 default: /* something wrong */
1020 return cur_pos; /* don't have to move */
1023 { /* convert backward into forward */
1024 if (zzip_rewind(fp) == -1)
1027 read_size = cur_pos + rel_ofs;
1030 { /* amount to read is positive relative offset */
1031 read_size = rel_ofs;
1034 if (read_size < 0) /* bad offset, before beginning of file */
1037 if (read_size + cur_pos > (zzip_off_t) fp->usize) /* bad offset, past EOF */
1040 if (read_size == 0) /* nothing to read */
1045 * If this is other handle than previous, save current seek pointer
1046 * and read the file position of `this' handle.
1048 if (dir->currentfp != fp)
1050 if (zzip_file_saveoffset(dir->currentfp) < 0
1051 || dir->currentfp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
1052 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
1054 { dir->currentfp = fp; }
1057 if (fp->method == 0)
1058 { /* unstore, just lseek relatively */
1059 ofs = fp->io->fd.tells(dir->fd);
1060 ofs = fp->io->fd.seeks(dir->fd, read_size, SEEK_CUR);
1062 { /* readjust from beginning of file */
1063 ofs -= fp->dataoffset;
1064 fp->restlen = fp->usize - ofs;
1068 { /* method == 8, inflate */
1071 /*FIXME: use a static buffer! */
1072 buf = (char *) malloc(ZZIP_32K);
1076 while (read_size > 0)
1078 zzip_off_t size = ZZIP_32K;
1080 if (read_size < size /*32K */ )
1083 size = zzip_file_read(fp, buf, (zzip_size_t) size);
1085 { free(buf); return -1; }
1093 return zzip_tell(fp);
1097 * This function will => tell(2) the current position in a real/zipped file
1099 * It will return the current offset within the real/zipped file,
1100 * measured in uncompressed bytes for the zipped-file case.
1102 * If the file-handle is wrapping a stat'able file then it will actually just
1103 * perform a normal => tell(2)-call, otherwise the offset is
1104 * calculated from the amount of data left and the total uncompressed
1108 zzip_tell(ZZIP_FILE * fp)
1113 if (! fp->dir) /* stat fd */
1114 return fp->io->fd.tells(fp->fd);
1116 /* current uncompressed offset is uncompressed size - data left */
1117 return (fp->usize - fp->restlen);
1122 * c-file-style: "stroustrup"