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
);
106 /* user-definition */
107 #ifndef ZZIP_BACKSLASH_DIRSEP
108 #if defined HAVE_WINDOWS_H || defined ZZIP_HAVE_WINDOWS_H || defined _WIN32
109 #define ZZIP_BACKSLASH_DIRSEP 1
110 #elif defined ZZIP_CHECK_BACKSLASH_DIRSEPARATOR
111 #define ZZIP_BACKSLASH_DIRSEP 1
113 #define ZZIP_BACKSLASH_DIRSEP 0
118 strrchr_basename(zzip_char_t
* name
)
120 register zzip_char_t
*n
= strrchr(name
, '/');
126 dirsep_basename(zzip_char_t
* name
)
128 register zzip_char_t
*n
= strrchr(name
, '/');
130 if (ZZIP_BACKSLASH_DIRSEP
)
132 register zzip_char_t
*m
= strrchr(name
, '\\');
133 if (!n
|| (m
&& n
< m
))
141 #if defined strcasecmp
142 #define dirsep_strcasecmp strcasecmp
145 dirsep_strcasecmp(zzip_char_t
* s1
, zzip_char_t
* s2
)
147 /* ASCII tolower - including mapping of backslash in normal slash */
148 static const char mapping
[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
153 c1
= (int) (unsigned char) *s1
;
154 c2
= (int) (unsigned char) *s2
;
155 if ((c1
& 0xE0) == 0x40)
156 c1
= mapping
[c1
& 0x1f];
157 if ((c2
& 0xE0) == 0x40)
158 c2
= mapping
[c2
& 0x1f];
165 return (((int) (unsigned char) *s1
) - ((int) (unsigned char) *s2
));
169 static int zzip_inflate_init(ZZIP_FILE
*, struct zzip_dir_hdr
*);
172 * open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since
173 * we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
174 * this is the best choice to unpack multiple files.
176 * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
177 * memchunk here... just to be safe.
179 * On error it returns null and sets errcode in the ZZIP_DIR.
182 zzip_file_open(ZZIP_DIR
* dir
, zzip_char_t
* name
, int o_mode
)
185 zzip_error_t err
= 0;
186 struct zzip_file
*fp
= 0;
187 struct zzip_dir_hdr
*hdr
= dir
->hdr0
;
188 int (*filename_strcmp
) (zzip_char_t
*, zzip_char_t
*);
189 zzip_char_t
* (*filename_basename
)(zzip_char_t
*);
191 filename_strcmp
= (o_mode
& ZZIP_CASELESS
) ? dirsep_strcasecmp
: strcmp
;
192 filename_basename
= (o_mode
& ZZIP_CASELESS
) ? dirsep_basename
: strrchr_basename
;
196 if (! dir
->fd
|| dir
->fd
== -1)
197 { dir
->errcode
= EBADF
; return NULL
; }
199 { dir
->errcode
= ENOENT
; return NULL
; }
201 if (o_mode
& ZZIP_NOPATHS
)
202 name
= filename_basename(name
);
206 register zzip_char_t
*hdr_name
= hdr
->d_name
;
208 if (o_mode
& ZZIP_NOPATHS
)
209 hdr_name
= filename_basename(hdr_name
);
211 HINT4("name='%s', compr=%d, size=%d\n",
212 hdr
->d_name
, hdr
->d_compr
, hdr
->d_usize
);
214 if (! filename_strcmp(hdr_name
, name
))
216 switch (hdr
->d_compr
)
219 case 8: /* inflate */
222 { err
= ZZIP_UNSUPP_COMPR
; goto error
; }
225 if (dir
->cache
.locked
== NULL
)
226 dir
->cache
.locked
= &self
;
228 if (dir
->cache
.locked
== &self
&& dir
->cache
.fp
)
231 dir
->cache
.fp
= NULL
;
232 /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
235 if (! (fp
= (ZZIP_FILE
*) calloc(1, sizeof(*fp
))))
236 { err
= ZZIP_OUTOFMEM
; goto error
; }
243 if (dir
->cache
.locked
== &self
&& dir
->cache
.buf32k
)
245 fp
->buf32k
= dir
->cache
.buf32k
;
246 dir
->cache
.buf32k
= NULL
;
249 if (! (fp
->buf32k
= (char *) malloc(ZZIP_32K
)))
250 { err
= ZZIP_OUTOFMEM
; goto error
; }
253 if (dir
->cache
.locked
== &self
)
254 dir
->cache
.locked
= NULL
;
256 * In order to support simultaneous open files in one zip archive
257 * we'll fix the fd offset when opening new file/changing which
261 if (zzip_file_saveoffset(dir
->currentfp
) < 0)
262 { err
= ZZIP_DIR_SEEK
; goto error
; }
264 fp
->offset
= hdr
->d_off
;
267 if (dir
->io
->fd
.seeks(dir
->fd
, hdr
->d_off
, SEEK_SET
) < 0)
268 { err
= ZZIP_DIR_SEEK
; goto error
; }
271 /* skip local header - should test tons of other info,
272 * but trust that those are correct */
273 zzip_ssize_t dataoff
;
274 struct zzip_file_header
*p
= (void *) fp
->buf32k
;
276 dataoff
= dir
->io
->fd
.read(dir
->fd
, (void *) p
, sizeof(*p
));
277 if (dataoff
< (zzip_ssize_t
) sizeof(*p
))
278 { err
= ZZIP_DIR_READ
; goto error
; }
279 if (! zzip_file_header_check_magic(p
)) /* PK\3\4 */
280 { err
= ZZIP_CORRUPTED
; goto error
; }
282 dataoff
= zzip_file_header_sizeof_tail(p
);
284 if (dir
->io
->fd
.seeks(dir
->fd
, dataoff
, SEEK_CUR
) < 0)
285 { err
= ZZIP_DIR_SEEK
; goto error
; }
287 fp
->dataoffset
= dir
->io
->fd
.tells(dir
->fd
);
288 fp
->usize
= hdr
->d_usize
;
289 fp
->csize
= hdr
->d_csize
;
292 err
= zzip_inflate_init(fp
, hdr
);
299 if (hdr
->d_reclen
== 0)
301 hdr
= (struct zzip_dir_hdr
*) ((char *) hdr
+ hdr
->d_reclen
);
302 } /*filename_strcmp */
304 dir
->errcode
= ZZIP_ENOENT
;
314 * call => inflateInit and setup fp's iterator variables,
315 * used by lowlevel => _open functions.
318 zzip_inflate_init(ZZIP_FILE
* fp
, struct zzip_dir_hdr
*hdr
)
322 fp
->method
= hdr
->d_compr
;
323 fp
->restlen
= hdr
->d_usize
;
327 memset(&fp
->d_stream
, 0, sizeof(fp
->d_stream
));
329 err
= inflateInit2(&fp
->d_stream
, -MAX_WBITS
);
333 fp
->crestlen
= hdr
->d_csize
;
343 * This function closes the given ZZIP_FILE handle.
345 * If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd
346 * that is being closed and the otherwise empty ZZIP_FILE gets freed.
349 zzip_fclose(ZZIP_FILE
* fp
)
353 if (! fp
->dir
) /* stat fd */
354 { int r
= fp
->io
->fd
.close(fp
->fd
); free(fp
); return r
; }
356 return zzip_file_close(fp
);
362 zzip_close(ZZIP_FILE
* fp
)
364 return zzip_fclose(fp
);
368 * This functions read data from zip-contained file.
370 * It works like => read(2) and will fill the given buffer with bytes from
371 * the opened file. It will return the number of bytes read, so if the => EOF
372 * is encountered you will be prompted with the number of bytes actually read.
374 * This is the routines that needs the => buf32k buffer, and it would have
375 * need for much more polishing but it does already work quite well.
377 * Note: the 32K buffer is rather big. The original inflate-algorithm
378 * required just that but the latest zlib would work just fine with
382 zzip_file_read(ZZIP_FILE
* fp
, void *buf
, zzip_size_t len
)
388 if (! fp
|| ! fp
->dir
)
392 l
= fp
->restlen
> len
? len
: fp
->restlen
;
393 if (fp
->restlen
== 0)
397 * If this is other handle than previous, save current seek pointer
398 * and read the file position of `this' handle.
400 if (dir
->currentfp
!= fp
)
402 if (zzip_file_saveoffset(dir
->currentfp
) < 0
403 || fp
->io
->fd
.seeks(dir
->fd
, fp
->offset
, SEEK_SET
) < 0)
404 { dir
->errcode
= ZZIP_DIR_SEEK
; return -1; }
406 { dir
->currentfp
= fp
; }
409 /* if more methods is to be supported, change this to `switch ()' */
410 if (fp
->method
) /* method != 0 == 8, inflate */
412 fp
->d_stream
.avail_out
= l
;
413 fp
->d_stream
.next_out
= (unsigned char *) buf
;
418 zzip_size_t startlen
;
420 if (fp
->crestlen
> 0 && fp
->d_stream
.avail_in
== 0)
422 zzip_size_t cl
= (fp
->crestlen
< ZZIP_32K
?
423 fp
->crestlen
: ZZIP_32K
);
425 * fp->crestlen > 128 ? 128 : fp->crestlen;
427 zzip_ssize_t i
= fp
->io
->fd
.read(dir
->fd
, fp
->buf32k
, cl
);
431 dir
->errcode
= ZZIP_DIR_READ
;
432 /* or ZZIP_DIR_READ_EOF ? */
436 fp
->d_stream
.avail_in
= i
;
437 fp
->d_stream
.next_in
= (unsigned char *) fp
->buf32k
;
440 startlen
= fp
->d_stream
.total_out
;
441 err
= inflate(&fp
->d_stream
, Z_NO_FLUSH
);
443 if (err
== Z_STREAM_END
)
445 else if (err
== Z_OK
)
446 { fp
->restlen
-= (fp
->d_stream
.total_out
- startlen
); }
448 { dir
->errcode
= err
; return -1; }
450 while (fp
->restlen
&& fp
->d_stream
.avail_out
);
452 return l
- fp
->d_stream
.avail_out
;
454 { /* method == 0 -- unstore */
455 rv
= fp
->io
->fd
.read(dir
->fd
, buf
, l
);
457 { fp
->restlen
-= rv
; }
459 { dir
->errcode
= ZZIP_DIR_READ
; }
465 * This function will read(2) data from a real/zipped file.
467 * the replacement for => read(2) will fill the given buffer with bytes from
468 * the opened file. It will return the number of bytes read, so if the EOF
469 * is encountered you will be prompted with the number of bytes actually read.
471 * If the file-handle is wrapping a stat'able file then it will actually just
472 * perform a normal => read(2)-call, otherwise => zzip_file_read is called
473 * to decompress the data stream and any error is mapped to => errno(3).
476 zzip_read(ZZIP_FILE
* fp
, void *buf
, zzip_size_t len
)
481 { return fp
->io
->fd
.read(fp
->fd
, buf
, len
); } /* stat fd */
484 register zzip_ssize_t v
;
486 v
= zzip_file_read(fp
, buf
, len
);
488 { errno
= zzip_errno(fp
->dir
->errcode
); }
496 zzip_fread(void *ptr
, zzip_size_t size
, zzip_size_t nmemb
, ZZIP_FILE
* file
)
500 return zzip_read(file
, ptr
, size
* nmemb
) / size
;
504 #define ZZIP_WRONLY O_WRONLY
505 #define ZZIP_EXCL O_EXCL
508 #define ZZIP_SYNC O_SYNC
513 #if defined O_NONBLOCK
514 #define ZZIP_NONBLOCK O_NONBLOCK
515 #elif defined O_NDELAY
516 #define ZZIP_NOCTTY O_NDELAY
518 #define ZZIP_NOCTTY 0
521 /* ------------------------------------------------------------------- */
524 * This function will => fopen(3) a real/zipped file.
526 * It has some magic functionality builtin - it will first try to open
527 * the given <em>filename</em> as a normal file. If it does not
528 * exist, the given path to the filename (if any) is split into
529 * its directory-part and the file-part. A ".zip" extension is
530 * then added to the directory-part to create the name of a
531 * zip-archive. That zip-archive (if it exists) is being searched
532 * for the file-part, and if found a zzip-handle is returned.
534 * Note that if the file is found in the normal fs-directory the
535 * returned structure is mostly empty and the => zzip_read call will
536 * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
537 * is performed and any error mapped to => errno(3).
539 * unlike the posix-wrapper => zzip_open the mode-argument is
540 * a string which allows for more freedom to support the extra
541 * zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
542 * Currently, this => zzip_fopen call will convert the following
543 * characters in the mode-string into their corrsponding mode-bits:
544 * * <code> "r" : O_RDONLY : </code> read-only
545 * * <code> "b" : O_BINARY : </code> binary (win32 specific)
546 * * <code> "f" : O_NOCTTY : </code> no char device (unix)
547 * * <code> "i" : ZZIP_CASELESS : </code> inside zip file
548 * * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
549 * all other modes will be ignored for zip-contained entries
550 * but they are transferred for compatibility and portability,
551 * including these extra sugar bits:
552 * * <code> "x" : O_EXCL :</code> fail if file did exist
553 * * <code> "s" : O_SYNC :</code> synchronized access
554 * * <code> "n" : O_NONBLOCK :</code> nonblocking access
555 * * <code> "z#" : compression level :</code> for zlib
556 * * <code> "g#" : group access :</code> unix access bits
557 * * <code> "u#" : owner access :</code> unix access bits
558 * * <code> "o#" : world access :</code> unix access bits
559 * ... the access bits are in traditional unix bit format
560 * with 7 = read/write/execute, 6 = read/write, 4 = read-only.
562 * The default access mode is 0664, and the compression level
563 * is ignored since the lib can not yet write zip files, otherwise
564 * it would be the initialisation value for the zlib deflateInit
565 * where 0 = no-compression, 1 = best-speed, 9 = best-compression.
567 * This function returns a new zzip-handle (use => zzip_close to return
568 * it). On error this function will return null setting => errno(3).
571 zzip_fopen(zzip_char_t
* filename
, zzip_char_t
* mode
)
573 return zzip_freopen(filename
, mode
, 0);
578 * This function receives an additional argument pointing to
579 * a ZZIP_FILE* being already in use. If this extra argument is
580 * null then this function is identical with calling => zzip_fopen
582 * Per default, the old file stream is closed and only the internal
583 * structures associated with it are kept. These internal structures
584 * may be reused for the return value, and this is a lot quicker when
585 * the filename matches a zipped file that is incidently in the very
586 * same zip arch as the old filename wrapped in the stream struct.
588 * That's simply because the zip arch's central directory does not
589 * need to be read again. As an extension for this function, if the
590 * mode-string contains a "q" then the old stream is not closed but
591 * left untouched, instead it is only given as a hint that a new
592 * file handle may share/copy the zip arch structures of the old file
593 * handle if that is possible, i.e when they are in the same zip arch.
595 * This function returns a new zzip-handle (use => zzip_close to return
596 * it). On error this function will return null setting => errno(3).
599 zzip_freopen(zzip_char_t
* filename
, zzip_char_t
* mode
, ZZIP_FILE
* stream
)
617 # define O_NONBLOCK 0
620 for (; *mode
; mode
++)
625 case '0': case '1': case '2': case '3': case '4':
626 case '5': case '6': case '7': case '8': case '9':
627 continue; /* ignore if not attached to other info */
628 case 'r': o_flags
|= mode
[1] == '+' ? O_RDWR
: O_RDONLY
; break;
629 case 'w': o_flags
|= mode
[1] == '+' ? O_RDWR
: O_WRONLY
;
630 o_flags
|= O_TRUNC
; break;
631 case 'b': o_flags
|= O_BINARY
; break;
632 case 'f': o_flags
|= O_NOCTTY
; break;
633 case 'i': o_modes
|= ZZIP_CASELESS
; break;
634 case '*': o_modes
|= ZZIP_NOPATHS
; break;
635 case 'x': o_flags
|= O_EXCL
; break;
636 case 's': o_flags
|= O_SYNC
; break;
637 case 'n': o_flags
|= O_NONBLOCK
; break;
638 case 'o': o_modes
&=~ 07;
639 o_modes
|= ((mode
[1] - '0')) & 07; continue;
640 case 'g': o_modes
&=~ 070;
641 o_modes
|= ((mode
[1] - '0') << 3) & 070; continue;
642 case 'u': o_modes
&=~ 0700;
643 o_modes
|= ((mode
[1] - '0') << 6) & 0700; continue;
644 case 'q': o_modes
|= ZZIP_FACTORY
; break;
645 case 'z': /* compression level */
646 continue; /* currently ignored, just for write mode */
653 zzip_open_shared_io(stream
, filename
, o_flags
, o_modes
, 0, 0);
655 if (! (o_modes
& ZZIP_FACTORY
) && stream
)
656 zzip_file_close(stream
);
663 * This function will => open(2) a real/zipped file
665 * It has some magic functionality builtin - it will first try to open
666 * the given <em>filename</em> as a normal file. If it does not
667 * exist, the given path to the filename (if any) is split into
668 * its directory-part and the file-part. A ".zip" extension is
669 * then added to the directory-part to create the name of a
670 * zip-archive. That zip-archive (if it exists) is being searched
671 * for the file-part, and if found a zzip-handle is returned.
673 * Note that if the file is found in the normal fs-directory the
674 * returned structure is mostly empty and the => zzip_read call will
675 * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
676 * is performed and any error mapped to => errno(3).
678 * There was a possibility to transfer zziplib-specific openmodes
679 * through o_flags but you should please not use them anymore and
680 * look into => zzip_open_ext_io to submit them down. This function
681 * is shallow in that it just extracts the zzipflags and calls
682 * * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
683 * you must stop using this extra functionality (not well known anyway)
684 * since zzip_open might be later usable to open files for writing
685 * in which case the _EXTRAFLAGS will get in conflict.
687 * compare with => open(2) and => zzip_fopen
690 zzip_open(zzip_char_t
* filename
, int o_flags
)
692 /* backward compatibility */
695 if (o_flags
& ZZIP_CASEINSENSITIVE
)
696 { o_flags
^= ZZIP_CASEINSENSITIVE
; o_modes
|= ZZIP_CASELESS
; }
697 if (o_flags
& ZZIP_IGNOREPATH
)
698 { o_flags
^= ZZIP_IGNOREPATH
; o_modes
|= ZZIP_NOPATHS
; }
699 return zzip_open_ext_io(filename
, o_flags
, o_modes
, 0, 0);
702 /* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
703 #if ZZIP_SIZEOF_INT+0 == 2
709 * This function uses explicit ext and io instead of the internal
710 * defaults, setting them to zero is equivalent to => zzip_open
712 * note that the two flag types have been split into an o_flags
713 * (for fcntl-like openflags) and o_modes where the latter shall
714 * carry the zzip_flags and possibly accessmodes for unix filesystems.
715 * Since this version of zziplib can not write zipfiles, it is not
716 * yet used for anything else than zzip-specific modeflags.
718 * This function returns a new zzip-handle (use => zzip_close to return
719 * it). On error this function will return null setting => errno(3).
721 * If any ext_io handlers were used then the referenced structure
722 * should be static as the allocated ZZIP_FILE does not copy them.
725 zzip_open_ext_io(zzip_char_t
* filename
, int o_flags
, int o_modes
,
726 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
728 return zzip_open_shared_io(0, filename
, o_flags
, o_modes
, ext
, io
);
733 * This function takes an extra stream argument - if a handle has been
734 * then ext/io can be left null and the new stream handle will pick up
735 * the ext/io. This should be used only in specific environment however
736 * since => zzip_file_real does not store any ext-sequence.
738 * The benefit for this function comes in when the old file handle
739 * was openened from a file within a zip archive. When the new file
740 * is in the same zip archive then the internal zzip_dir structures
741 * will be shared. It is even quicker, as no check needs to be done
742 * anymore trying to guess the zip archive place in the filesystem,
743 * here we just check whether the zip archive's filepath is a prefix
744 * part of the filename to be opened.
746 * Note that this function is also used by => zzip_freopen that
747 * will unshare the old handle, thereby possibly closing the handle.
749 * This function returns a new zzip-handle (use => zzip_close to return
750 * it). On error this function will return null setting => errno(3).
753 zzip_open_shared_io(ZZIP_FILE
* stream
,
754 zzip_char_t
* filename
, int o_flags
, int o_modes
,
755 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
757 if (stream
&& stream
->dir
)
760 ext
= stream
->dir
->fileext
;
762 io
= stream
->dir
->io
;
765 io
= zzip_get_default_io();
767 if (o_modes
& (ZZIP_PREFERZIP
| ZZIP_ONLYZIP
))
770 /* prefer an existing real file */
772 zzip_plugin_io_t os
= (o_modes
& ZZIP_ALLOWREAL
)
773 ? zzip_get_default_io() : io
;
774 int fd
= (os
->fd
.open
)(filename
, o_flags
); /* io->fd.open */
778 ZZIP_FILE
*fp
= calloc(1, sizeof(ZZIP_FILE
));
781 { os
->fd
.close(fd
); return 0; } /* io->fd.close */
787 if (o_modes
& ZZIP_PREFERZIP
)
792 /* if the user had it in place of a normal xopen, then
793 * we better defend this lib against illegal usage */
794 if (o_flags
& (O_CREAT
| O_WRONLY
))
795 { errno
= EINVAL
; return 0; }
796 if (o_flags
& (O_RDWR
))
797 { o_flags
^= O_RDWR
; o_flags
|= O_RDONLY
; }
799 /* this is just for backward compatibility -and strictly needed to
800 * prepare ourselves for more options and more options later on... */
801 /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
802 /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */
804 /* see if we can open a file that is a zip file */
806 char basename
[PATH_MAX
];
808 int filename_len
= strlen(filename
);
810 if (filename_len
>= PATH_MAX
)
811 { errno
= ENAMETOOLONG
; return 0; }
812 memcpy(basename
, filename
, filename_len
+ 1);
814 /* see if we can share the same zip directory */
815 if (stream
&& stream
->dir
&& stream
->dir
->realname
)
817 zzip_size_t len
= strlen(stream
->dir
->realname
);
819 if (! memcmp(filename
, stream
->dir
->realname
, len
) &&
820 filename
[len
] == '/' && filename
[len
+ 1])
823 zzip_file_open(stream
->dir
, filename
+ len
+ 1, o_modes
);
825 { errno
= zzip_errno (stream
->dir
->errcode
); }
830 /* per each slash in filename, check if it there is a zzip around */
831 while ((p
= strrchr(basename
, '/')))
839 /* i.e. cut at path separator == possible zipfile basename */
840 fd
= __zzip_try_open(basename
, o_flags
| O_RDONLY
| O_BINARY
,
845 /* found zip-file .... now try to parse it */
846 dir
= zzip_dir_fdopen_ext_io(fd
, &e
, ext
, io
);
848 { errno
= zzip_errno(e
); io
->fd
.close(fd
); return 0; }
850 /* (p - basename) is the lenghtof zzip_dir part of the filename */
851 fp
= zzip_file_open(dir
, filename
+ (p
- basename
) + 1, o_modes
);
853 { errno
= zzip_errno(dir
->errcode
); }
855 { if (! dir
->realname
) dir
->realname
= strdup (basename
); }
858 /* note: since (fp) is attached that (dir) will survive */
859 /* but (dir) is implicitly closed on next zzip_close(fp) */
864 if (o_modes
& ZZIP_PREFERZIP
)
867 { errno
= ENOENT
; return 0; }
871 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
872 #undef zzip_open_shared_io /* zzip_open_shared_io64 */
873 #undef zzip_open_ext_io /* zzip_open_ext_io64 */
874 #undef zzip_opendir_ext_io /* zzip_opendir_ext_io64 */
876 ZZIP_FILE
*zzip_open_shared_io(ZZIP_FILE
* stream
,
877 zzip_char_t
* name
, int o_flags
,
878 int o_modes
, zzip_strings_t
* ext
,
879 zzip_plugin_io_t io
);
880 ZZIP_FILE
*zzip_open_ext_io(zzip_char_t
* name
, int o_flags
,
881 int o_modes
, zzip_strings_t
* ext
,
882 zzip_plugin_io_t io
);
883 ZZIP_DIR
*zzip_opendir_ext_io(zzip_char_t
* name
, int o_modes
,
884 zzip_strings_t
* ext
, zzip_plugin_io_t io
);
886 /* DLL compatibility layer - so that 32bit code can link with this lib too */
889 zzip_open_shared_io(ZZIP_FILE
* stream
,
890 zzip_char_t
* name
, int o_flags
,
891 int o_modes
, zzip_strings_t
* ext
, zzip_plugin_io_t io
)
894 return zzip_open_shared_io64(stream
, name
, o_flags
, o_modes
, ext
, io
);
900 zzip_open_ext_io(zzip_char_t
* name
, int o_flags
, int o_modes
,
901 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
904 return zzip_open_ext_io64(name
, o_flags
, o_modes
, ext
, io
);
910 zzip_opendir_ext_io(zzip_char_t
* name
, int o_modes
,
911 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
914 return zzip_opendir_ext_io64(name
, o_modes
, ext
, io
);
916 { errno
= EOVERFLOW
; return NULL
; }
919 #endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
921 /* ------------------------------------------------------------------- */
924 * This function will rewind a real/zipped file.
926 * It seeks to the beginning of this file's data in the zip,
927 * or the beginning of the file for a stat'fd.
930 zzip_rewind(ZZIP_FILE
* fp
)
940 fp
->io
->fd
.seeks(fp
->fd
, 0, SEEK_SET
);
946 * If this is other handle than previous, save current seek pointer
948 if (dir
->currentfp
!= fp
)
950 if (zzip_file_saveoffset(dir
->currentfp
) < 0)
951 { dir
->errcode
= ZZIP_DIR_SEEK
; return -1; }
953 { dir
->currentfp
= fp
; }
956 /* seek to beginning of this file */
957 if (fp
->io
->fd
.seeks(dir
->fd
, fp
->dataoffset
, SEEK_SET
) < 0)
960 /* reset the inflate init stuff */
961 fp
->restlen
= fp
->usize
;
962 fp
->offset
= fp
->dataoffset
;
965 { /* method == 8, deflate */
966 err
= inflateReset(&fp
->d_stream
);
970 /* start over at next inflate with a fresh read() */
971 fp
->d_stream
.avail_in
= 0;
972 fp
->crestlen
= fp
->csize
;
984 * This function will perform a => lseek(2) operation on a real/zipped file
986 * It will try to seek to the offset specified by offset, relative to whence,
987 * which is one of SEEK_SET, SEEK_CUR or SEEK_END.
989 * If the file-handle is wrapping a stat'able file then it will actually just
990 * perform a normal => lseek(2)-call. Otherwise the relative offset
991 * is calculated, negative offsets are transformed into positive ones
992 * by rewinding the file, and then data is read until the offset is
993 * reached. This can make the function terribly slow, but this is
994 * how gzio implements it, so I'm not sure there is a better way
995 * without using the internals of the algorithm.
998 zzip_seek(ZZIP_FILE
* fp
, zzip_off_t offset
, int whence
)
1000 zzip_off_t cur_pos
, rel_ofs
, read_size
, ofs
;
1008 return fp
->io
->fd
.seeks(fp
->fd
, offset
, whence
);
1011 cur_pos
= zzip_tell(fp
);
1013 /* calculate relative offset */
1016 case SEEK_SET
: /* from beginning */
1017 rel_ofs
= offset
- cur_pos
;
1019 case SEEK_CUR
: /* from current */
1022 case SEEK_END
: /* from end */
1023 rel_ofs
= fp
->usize
+ offset
- cur_pos
;
1025 default: /* something wrong */
1030 return cur_pos
; /* don't have to move */
1033 { /* convert backward into forward */
1034 if (zzip_rewind(fp
) == -1)
1037 read_size
= cur_pos
+ rel_ofs
;
1040 { /* amount to read is positive relative offset */
1041 read_size
= rel_ofs
;
1044 if (read_size
< 0) /* bad offset, before beginning of file */
1047 if (read_size
+ cur_pos
> (zzip_off_t
) fp
->usize
) /* bad offset, past EOF */
1050 if (read_size
== 0) /* nothing to read */
1055 * If this is other handle than previous, save current seek pointer
1056 * and read the file position of `this' handle.
1058 if (dir
->currentfp
!= fp
)
1060 if (zzip_file_saveoffset(dir
->currentfp
) < 0
1061 || fp
->io
->fd
.seeks(dir
->fd
, fp
->offset
, SEEK_SET
) < 0)
1062 { dir
->errcode
= ZZIP_DIR_SEEK
; return -1; }
1064 { dir
->currentfp
= fp
; }
1067 if (fp
->method
== 0)
1068 { /* unstore, just lseek relatively */
1069 ofs
= fp
->io
->fd
.tells(dir
->fd
);
1070 ofs
= fp
->io
->fd
.seeks(dir
->fd
, read_size
, SEEK_CUR
);
1072 { /* readjust from beginning of file */
1073 ofs
-= fp
->dataoffset
;
1074 fp
->restlen
= fp
->usize
- ofs
;
1078 { /* method == 8, inflate */
1081 /*FIXME: use a static buffer! */
1082 buf
= (char *) malloc(ZZIP_32K
);
1086 while (read_size
> 0)
1088 zzip_off_t size
= ZZIP_32K
;
1090 if (read_size
< size
/*32K */ )
1093 size
= zzip_file_read(fp
, buf
, (zzip_size_t
) size
);
1095 { free(buf
); return -1; }
1103 return zzip_tell(fp
);
1107 * This function will => tell(2) the current position in a real/zipped file
1109 * It will return the current offset within the real/zipped file,
1110 * measured in uncompressed bytes for the zipped-file case.
1112 * If the file-handle is wrapping a stat'able file then it will actually just
1113 * perform a normal => tell(2)-call, otherwise the offset is
1114 * calculated from the amount of data left and the total uncompressed
1118 zzip_tell(ZZIP_FILE
* fp
)
1123 if (! fp
->dir
) /* stat fd */
1124 return fp
->io
->fd
.tells(fp
->fd
);
1126 /* current uncompressed offset is uncompressed size - data left */
1127 return (fp
->usize
- fp
->restlen
);
1131 #define EOVERFLOW EFBIG
1135 * This function is provided for users who can not use any largefile-mode.
1138 zzip_tell32(ZZIP_FILE
* fp
)
1140 if (sizeof(zzip_off_t
) == sizeof(long))
1142 return zzip_tell(fp
);
1145 off_t off
= zzip_tell(fp
);
1147 register long off32
= off
;
1148 if (off32
== off
) return off32
;
1156 * This function is provided for users who can not use any largefile-mode.
1159 zzip_seek32(ZZIP_FILE
* fp
, long offset
, int whence
)
1161 if (sizeof(zzip_off_t
) == sizeof(long))
1163 return zzip_seek(fp
, offset
, whence
);
1166 off_t off
= zzip_seek(fp
, offset
, whence
);
1168 register long off32
= off
;
1169 if (off32
== off
) return off32
;
1178 * c-file-style: "stroustrup"