3 * Guido Draheim <guidod@gmx.de>
4 * Tomi Ollila <too@iki.fi>
6 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
8 * use under the restrictions of the
9 * Lesser GNU General Public License
10 * or alternatively the restrictions
11 * of the Mozilla Public License 1.1
14 #include <zzip/lib.h> /* archive handling */
15 #include <zzip/file.h>
16 #include <zzip/format.h>
17 #include <zzip/fetch.h>
24 #ifdef ZZIP_HAVE_SYS_STAT_H
28 #include <zzip/__mmap.h>
29 #include <zzip/__debug.h>
31 #define __sizeof(X) ((zzip_ssize_t)(sizeof(X)))
33 /* per default, we use a little hack to correct bad z_rootseek parts */
34 #define ZZIP_CORRECT_ROOTSEEK 1
36 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ >= 4)
38 # warning suppress a warning where the compiler should have optimized instead.
45 #define ZZIP_DISK64_TRAILER
47 #ifdef ZZIP_DISK64_TRAILER
48 struct _disk_trailer {
50 void* zz_for_correct_rootseek; // ZZIP_CORRECT_ROOTSEEK
51 zzip_off64_t zz_entries;
52 zzip_off64_t zz_finalentries;
53 zzip_off64_t zz_rootseek;
54 zzip_off64_t zz_rootsize;
56 #define _disk_trailer_entries(__p) ((__p)->zz_entries)
57 #define _disk_trailer_localentries(__p) ((__p)->zz_entries)
58 #define _disk_trailer_finalentries(__p) ((__p)->zz_entries)
59 #define _disk_trailer_rootseek(__p) ((__p)->zz_rootseek)
60 #define _disk_trailer_rootsize(__p) ((__p)->zz_rootsize)
61 #define _disk_trailer_set_rootseek(__p,__v) ((__p)->rootseek = (__v))
64 #define _disk_trailer zzip_disk_trailer
65 #define _disk_trailer_entries zzip_disk_trailer_entries
66 #define _disk_trailer_localentries zzip_disk_trailer_localentries
67 #define _disk_trailer_finalentries zzip_disk_trailer_finalentries
68 #define _disk_trailer_rootseek zzip_disk_trailer_rootseek
69 #define _disk_trailer_rootsize zzip_disk_trailer_rootsize
70 #define _disk_trailer_set_rootseek zzip_disk_trailer_set_rootseek
71 #define __zzip_fetch_disk_trailer __zzip_find_disk_trailer
74 /* --------------------------- internals -------------------------------- */
75 /* internal functions of zziplib, avoid at all cost, changes w/o warning.
76 * we do export them for debugging purpose and special external tools
77 * which know what they do and which can adapt from version to version
80 int __zzip_fetch_disk_trailer( int fd, zzip_off_t filesize,
81 struct _disk_trailer * _zzip_restrict trailer,
83 int __zzip_parse_root_directory( int fd,
84 struct _disk_trailer * trailer,
85 struct zzip_dir_hdr ** hdr_return,
88 _zzip_inline char* __zzip_aligned4(char* p);
90 /* ------------------------ harden routines ------------------------------ */
94 * check for inconsistent values in trailer and prefer lower seek value
95 * - we fix values assuming the root directory was written at the end
96 * and it is just before the zip trailer. Therefore, ...
98 _zzip_inline static void __fixup_rootseek(
99 zzip_off_t offset_of_trailer,
100 struct _disk_trailer* trailer)
102 if ( _disk_trailer_rootseek (trailer) >
103 offset_of_trailer - _disk_trailer_rootsize (trailer) &&
104 offset_of_trailer > _disk_trailer_rootsize (trailer))
106 register zzip_off_t offset;
107 offset = offset_of_trailer - _disk_trailer_rootsize (trailer);
108 _disk_trailer_set_rootseek (trailer, offset);
109 HINT2("new rootseek=%li", (long) _disk_trailer_rootseek (trailer));
112 #define __correct_rootseek(A,B,C)
114 #elif defined ZZIP_CORRECT_ROOTSEEK
115 /* store the seekvalue of the trailer into the "z_magic" field and with
116 * a 64bit off_t we overwrite z_disk/z_finaldisk as well. If you change
117 * anything in zziplib or dump the trailer structure then watch out that
118 * these are still unused, so that this code may still (ab)use those. */
119 #define __fixup_rootseek(_offset_of_trailer, _trailer) \
120 *(zzip_off_t*)_trailer = _offset_of_trailer;
121 #define __correct_rootseek( _u_rootseek, _u_rootsize, _trailer) \
122 if (_u_rootseek > *(zzip_off_t*)_trailer - _u_rootsize) \
123 _u_rootseek = *(zzip_off_t*)_trailer - _u_rootsize;
125 #define __fixup_rootseek(A,B)
126 #define __correct_rootseek(A,B,C)
131 _zzip_inline static void __debug_dir_hdr (struct zzip_dir_hdr* hdr)
133 if (sizeof(struct zzip_dir_hdr) > sizeof(struct zzip_disk_entry))
134 { WARN1("internal sizeof-mismatch may break wreakage"); }
135 /* the internal directory structure is never bigger than the
136 * external zip central directory space had been beforehand
137 * (as long as the following assertion holds...)
140 if (((zzip_off_t)hdr)&3)
141 { NOTE1("this machine's malloc(3) returns sth. not u32-aligned"); }
142 /* we assume that if this machine's malloc has returned a non-aligned
143 * memory block, then it is actually safe to access misaligned data, and
144 * since it does only affect the first hdr it should not even bring about
145 * too much of that cpu's speed penalty
149 #define __debug_dir_hdr(X)
152 /* -------------------------- low-level interface -------------------------- */
155 #if BUFSIZ == 1024 || BUFSIZ == 512 || BUFSIZ == 256
156 #define ZZIP_BUFSIZ BUFSIZ
161 #define ZZIP_BUFSIZ 512
162 /* #define ZZIP_BUFSIZ 64 */ /* for testing */
166 * This function is used by => zzip_file_open. It tries to find
167 * the zip's central directory info that is usually a few
168 * bytes off the end of the file.
171 __zzip_fetch_disk_trailer(int fd, zzip_off_t filesize,
172 struct _disk_trailer * _zzip_restrict trailer,
176 #define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; }
178 #define return(val) { e=val; goto cleanup; }
183 auto char buffer[2*ZZIP_BUFSIZ];
186 char* buf = malloc(2*ZZIP_BUFSIZ);
188 zzip_off_t offset = 0;
189 zzip_ssize_t maplen = 0; /* mmap(),read(),getpagesize() use size_t !! */
195 if (filesize < __sizeof(struct zzip_disk_trailer))
196 { return(ZZIP_DIR_TOO_SHORT); }
199 { return(ZZIP_OUTOFMEM); }
201 offset = filesize; /* a.k.a. old offset */
202 while(1) /* outer loop */
204 register unsigned char* mapped;
206 if (offset <= 0) { return(ZZIP_DIR_EDH_MISSING); }
208 /* trailer cannot be farther away than 64K from fileend */
209 if (filesize-offset > 64*1024)
210 { return(ZZIP_DIR_EDH_MISSING); }
212 /* the new offset shall overlap with the area after the old offset! */
213 if (USE_MMAP && io->fd.sys)
215 zzip_off_t mapoff = offset;
217 zzip_ssize_t pagesize = _zzip_getpagesize (io->fd.sys);
218 if (pagesize < ZZIP_BUFSIZ) goto non_mmap; /* an error? */
219 if (mapoff == filesize && filesize > pagesize)
221 if (mapoff < pagesize) {
222 maplen = (zzip_ssize_t)mapoff + pagesize; mapoff = 0;
224 mapoff -= pagesize; maplen = 2*pagesize;
225 if ((zzip_ssize_t)mapoff & (pagesize-1)) { /*only 1. run */
226 pagesize -= (zzip_ssize_t)mapoff & (pagesize-1);
231 if (mapoff + maplen > filesize) maplen = filesize - mapoff;
234 fd_map = _zzip_mmap(io->fd.sys, fd, mapoff, (zzip_size_t)maplen);
235 if (fd_map == MAP_FAILED) goto non_mmap;
236 mapped = (unsigned char*) fd_map; offset = mapoff; /* success */
237 HINT3("mapped *%p len=%li", fd_map, (long) maplen);
240 fd_map = 0; /* have no mmap */
242 zzip_off_t pagesize = ZZIP_BUFSIZ;
243 if (offset == filesize && filesize > pagesize)
245 if (offset < pagesize) {
246 maplen = (zzip_ssize_t)offset + pagesize; offset = 0;
248 offset -= pagesize; maplen = 2*pagesize;
249 if ((zzip_ssize_t)offset & (pagesize-1)) { /*on 1st run*/
250 pagesize -= (zzip_ssize_t)offset & (pagesize-1);
255 if (offset + maplen > filesize) maplen = filesize - offset;
258 if (io->fd.seeks(fd, offset, SEEK_SET) < 0)
259 { return(ZZIP_DIR_SEEK); }
260 if (io->fd.read(fd, buf, (zzip_size_t)maplen) < maplen)
261 { return(ZZIP_DIR_READ); }
262 mapped = (unsigned char*) buf; /* success */
263 HINT5("offs=$%lx len=%li filesize=%li pagesize=%i",
264 (long)offset, (long)maplen, (long)filesize, ZZIP_BUFSIZ);
267 {/* now, check for the trailer-magic, hopefully near the end of file */
268 register unsigned char* end = mapped + maplen;
269 register unsigned char* tail;
270 for (tail = end-1; (tail >= mapped); tail--)
272 if ((*tail == 'P') && /* quick pre-check for trailer magic */
273 end-tail >= __sizeof(struct zzip_disk_trailer)-2 &&
274 zzip_disk_trailer_check_magic(tail))
276 # ifndef ZZIP_DISK64_TRAILER
277 /* if the file-comment is not present, it happens
278 that the z_comment field often isn't either */
279 if (end-tail >= __sizeof(*trailer))
281 memcpy (trailer, tail, sizeof(*trailer));
283 memcpy (trailer, tail, sizeof(*trailer)-2);
284 trailer->z_comment[0] = 0;
285 trailer->z_comment[1] = 0;
288 struct zzip_disk_trailer* orig = (struct zzip_disk_trailer*) tail;
289 trailer->zz_tail = tail;
290 trailer->zz_entries = zzip_disk_trailer_localentries (orig);
291 trailer->zz_finalentries = zzip_disk_trailer_finalentries (orig);
292 trailer->zz_rootseek = zzip_disk_trailer_rootseek (orig);
293 trailer->zz_rootsize = zzip_disk_trailer_rootsize (orig);
296 __fixup_rootseek (offset + tail-mapped, trailer);
298 } else if ((*tail == 'P') &&
299 end-tail >= __sizeof(struct zzip_disk64_trailer)-2 &&
300 zzip_disk64_trailer_check_magic(tail))
302 # ifndef ZZIP_DISK64_TRAILER
303 return(ZZIP_DIR_LARGEFILE);
305 struct zzip_disk64_trailer* orig = (struct zzip_disk64_trailer*) tail;
306 trailer->zz_tail = tail;
307 trailer->zz_entries = zzip_disk64_trailer_localentries (orig);
308 trailer->zz_finalentries = zzip_disk64_trailer_finalentries (orig);
309 trailer->zz_rootseek = zzip_disk64_trailer_rootseek (orig);
310 trailer->zz_rootsize = zzip_disk64_trailer_rootsize (orig);
317 if (USE_MMAP && fd_map)
319 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
320 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t)maplen);
326 if (USE_MMAP && fd_map)
328 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
329 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t)maplen);
339 * making pointer alignments to values that can be handled as structures
340 * is tricky. We assume here that an align(4) is sufficient even for
341 * 64 bit machines. Note that binary operations are not usually allowed
342 * to pointer types but we do need only the lower bits in this implementation,
343 * so we can just cast the value to a long value.
345 _zzip_inline char* __zzip_aligned4(char* p)
347 #define aligned4 __zzip_aligned4
348 p += ((long)p)&1; /* warnings about truncation of a "pointer" */
349 p += ((long)p)&2; /* to a "long int" may be safely ignored :) */
354 * This function is used by => zzip_file_open, it is usually called after
355 * => __zzip_find_disk_trailer. It will parse the zip's central directory
356 * information and create a zziplib private directory table in
360 __zzip_parse_root_directory(int fd,
361 struct _disk_trailer * trailer,
362 struct zzip_dir_hdr ** hdr_return,
365 auto struct zzip_disk_entry dirent;
366 struct zzip_dir_hdr * hdr;
367 struct zzip_dir_hdr * hdr0;
368 uint16_t * p_reclen = 0;
369 unsigned long entries; /* 32bit is enough */
370 zzip_off64_t zz_offset; /* offset from start of root directory */
372 zzip_off64_t zz_fd_gap = 0;
373 zzip_off64_t zz_entries = _disk_trailer_localentries (trailer);
374 zzip_off64_t zz_rootsize = _disk_trailer_rootsize (trailer);
375 zzip_off64_t zz_rootseek = _disk_trailer_rootseek (trailer);
376 __correct_rootseek (zz_rootseek, zz_rootsize, trailer);
378 hdr0 = (struct zzip_dir_hdr*) malloc(zz_rootsize);
381 hdr = hdr0; __debug_dir_hdr (hdr);
383 if (USE_MMAP && io->fd.sys)
385 zz_fd_gap = zz_rootseek & (_zzip_getpagesize(io->fd.sys)-1) ;
386 HINT4(" fd_gap=%ld, mapseek=0x%lx, maplen=%ld", (long)(zz_fd_gap),
387 (long)(zz_rootseek-zz_fd_gap), (long)(zz_rootsize+zz_fd_gap));
388 fd_map = _zzip_mmap(io->fd.sys, fd,
389 zz_rootseek-zz_fd_gap, zz_rootsize+zz_fd_gap);
390 /* if mmap failed we will fallback to seek/read mode */
391 if (fd_map == MAP_FAILED) {
392 NOTE2("map failed: %s",strerror(errno));
395 HINT3("mapped *%p len=%li", fd_map, (long)(zz_rootsize+zz_fd_gap));
399 for (entries=zz_entries, zz_offset=0; entries; entries--)
401 register struct zzip_disk_entry * d;
402 uint16_t u_extras, u_comment, u_namlen;
405 { d = (void*)(fd_map+zz_fd_gap+zz_offset); } /* fd_map+fd_gap==u_rootseek */
408 if (io->fd.seeks(fd, zz_rootseek+zz_offset, SEEK_SET) < 0)
409 return ZZIP_DIR_SEEK;
410 if (io->fd.read(fd, &dirent, sizeof(dirent)) < __sizeof(dirent))
411 return ZZIP_DIR_READ;
415 if ((zzip_off64_t)(zz_offset+sizeof(*d)) > zz_rootsize ||
416 (zzip_off64_t)(zz_offset+sizeof(*d)) < 0)
417 { FAIL4("%li's entry stretches beyond root directory (O:%li R:%li)",
418 (long)entries, (long)(zz_offset), (long)zz_rootsize); break;}
420 # if 0 && defined DEBUG
421 zzip_debug_xbuf ((unsigned char*) d, sizeof(*d) + 8);
424 u_extras = zzip_disk_entry_get_extras (d);
425 u_comment = zzip_disk_entry_get_comment (d);
426 u_namlen = zzip_disk_entry_get_namlen (d);
427 HINT5("offset=0x%lx, size %ld, dirent *%p, hdr %p\n",
428 (long)(zz_offset+zz_rootseek), (long)zz_rootsize, d, hdr);
430 /* writes over the read buffer, Since the structure where data is
431 copied is smaller than the data in buffer this can be done.
432 It is important that the order of setting the fields is considered
433 when filling the structure, so that some data is not trashed in
434 first structure read.
435 at the end the whole copied list of structures is copied into
436 newly allocated buffer */
437 hdr->d_crc32 = zzip_disk_entry_get_crc32 (d);
438 hdr->d_csize = zzip_disk_entry_get_csize (d);
439 hdr->d_usize = zzip_disk_entry_get_usize (d);
440 hdr->d_off = zzip_disk_entry_get_offset (d);
441 hdr->d_compr = zzip_disk_entry_get_compr (d);
442 if (hdr->d_compr > _255) hdr->d_compr = 255;
444 if ((zzip_off64_t)(zz_offset+sizeof(*d) + u_namlen) > zz_rootsize ||
445 (zzip_off64_t)(zz_offset+sizeof(*d) + u_namlen) < 0)
446 { FAIL4("%li's name stretches beyond root directory (O:%li N:%li)",
447 (long)entries, (long)(zz_offset), (long)(u_namlen)); break; }
450 { memcpy(hdr->d_name, fd_map+zz_fd_gap + zz_offset+sizeof(*d), u_namlen); }
451 else { io->fd.read(fd, hdr->d_name, u_namlen); }
452 hdr->d_name[u_namlen] = '\0';
453 hdr->d_namlen = u_namlen;
455 /* update offset by the total length of this entry -> next entry */
456 zz_offset += sizeof(*d) + u_namlen + u_extras + u_comment;
458 if (zz_offset > zz_rootsize)
459 { FAIL3("%li's entry stretches beyond root directory (O:%li)",
460 (long)entries, (long)(zz_offset)); entries--; break; }
462 HINT5("file %ld { compr=%d crc32=$%x offset=%d",
463 (long)entries, hdr->d_compr, hdr->d_crc32, hdr->d_off);
464 HINT5("csize=%d usize=%d namlen=%d extras=%d",
465 hdr->d_csize, hdr->d_usize, u_namlen, u_extras);
466 HINT5("comment=%d name='%s' %s <sizeof %d> } ",
467 u_comment, hdr->d_name, "",(int) sizeof(*d));
469 p_reclen = &hdr->d_reclen;
471 { register char* p = (char*) hdr;
472 register char* q = aligned4 (p + sizeof(*hdr) + u_namlen + 1);
473 *p_reclen = (uint16_t)(q - p);
474 hdr = (struct zzip_dir_hdr*) q;
478 if (USE_MMAP && fd_map)
480 HINT3("unmap *%p len=%li", fd_map, (long)(zz_rootsize+zz_fd_gap));
481 _zzip_munmap(io->fd.sys, fd_map, zz_rootsize+zz_fd_gap);
486 *p_reclen = 0; /* mark end of list */
490 } /* else zero (sane) entries */
491 return (entries ? ZZIP_CORRUPTED : 0);
494 /* ------------------------- high-level interface ------------------------- */
500 static zzip_strings_t* zzip_get_default_ext(void)
502 static zzip_strings_t ext [] =
504 ".zip", ".ZIP", /* common extension */
505 # ifdef ZZIP_USE_ZIPLIKES
506 ".pk3", ".PK3", /* ID Software's Quake3 zipfiles */
507 ".jar", ".JAR", /* Java zipfiles */
516 * allocate a new ZZIP_DIR handle and do basic
517 * initializations before usage by => zzip_dir_fdopen
518 * => zzip_dir_open => zzip_file_open or through
520 * (ext==null flags uses { ".zip" , ".ZIP" } )
521 * (io ==null flags use of posix io defaults)
524 zzip_dir_alloc_ext_io (zzip_strings_t* ext, const zzip_plugin_io_t io)
527 if ((dir = (ZZIP_DIR *)calloc(1, sizeof(*dir))) == NULL)
530 /* dir->fileext is currently unused - so what, still initialize it */
531 dir->fileext = ext ? ext : zzip_get_default_ext();
532 dir->io = io ? io : zzip_get_default_io ();
536 /** => zzip_dir_alloc_ext_io
537 * this function is obsolete - it was generally used for implementation
538 * and exported to let other code build on it. It is now advised to
539 * use => zzip_dir_alloc_ext_io now on explicitly, just set that second
540 * argument to zero to achieve the same functionality as the old style.
543 zzip_dir_alloc (zzip_strings_t* fileext)
545 return zzip_dir_alloc_ext_io (fileext, 0);
549 * will free the zzip_dir handle unless there are still
550 * zzip_files attached (that may use its cache buffer).
551 * This is the inverse of => zzip_dir_alloc , and both
552 * are helper functions used implicitly in other zzipcalls
553 * e.g. => zzip_dir_close = zzip_close
555 * returns zero on sucess
556 * returns the refcount when files are attached.
559 zzip_dir_free(ZZIP_DIR * dir)
562 return (dir->refcount); /* still open files attached */
564 if (dir->fd >= 0) dir->io->fd.close(dir->fd);
565 if (dir->hdr0) free(dir->hdr0);
566 if (dir->cache.fp) free(dir->cache.fp);
567 if (dir->cache.buf32k) free(dir->cache.buf32k);
568 if (dir->realname) free(dir->realname);
574 * It will also => free(2) the => ZZIP_DIR-handle given.
575 * the counterpart for => zzip_dir_open
576 * see also => zzip_dir_free
579 zzip_dir_close(ZZIP_DIR * dir)
581 dir->refcount &=~ 0x10000000; /* explicit dir close */
582 return zzip_dir_free(dir);
586 * used by the => zzip_dir_open and zzip_opendir(2) call. Opens the
587 * zip-archive as specified with the fd which points to an
588 * already openend file. This function then search and parse
589 * the zip's central directory.
591 * NOTE: refcount is zero, so an _open/_close pair will also delete
595 zzip_dir_fdopen(int fd, zzip_error_t * errcode_p)
597 return zzip_dir_fdopen_ext_io(fd, errcode_p, 0, 0);
600 static zzip_error_t __zzip_dir_parse (ZZIP_DIR* dir); /* forward */
602 /** => zzip_dir_fdopen
603 * this function uses explicit ext and io instead of the internal
604 * defaults, setting these to zero is equivalent to => zzip_dir_fdopen
607 zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errcode_p,
608 zzip_strings_t* ext, const zzip_plugin_io_t io)
613 if ((dir = zzip_dir_alloc_ext_io (ext, io)) == NULL)
614 { rv = ZZIP_OUTOFMEM; goto error; }
617 if ((rv = __zzip_dir_parse (dir)))
620 dir->hdr = dir->hdr0;
621 dir->refcount |= 0x10000000;
623 if (errcode_p) *errcode_p = rv;
626 if (dir) zzip_dir_free(dir);
627 if (errcode_p) *errcode_p = rv;
632 __zzip_dir_parse (ZZIP_DIR* dir)
636 struct _disk_trailer trailer;
637 /* if (! dir || dir->fd < 0)
638 * { rv = EINVAL; goto error; }
641 HINT2("------------------ fd=%i", (int) dir->fd);
642 if ((filesize = dir->io->fd.filesize(dir->fd)) < 0)
643 { rv = ZZIP_DIR_STAT; goto error; }
645 HINT2("------------------ filesize=%ld", (long) filesize);
646 if ((rv = __zzip_fetch_disk_trailer(dir->fd, filesize, &trailer,
650 HINT5("directory = { entries= %ld/%ld, size= %ld, seek= %ld } ",
651 (long) _disk_trailer_localentries (&trailer),
652 (long) _disk_trailer_finalentries (&trailer),
653 (long) _disk_trailer_rootsize (&trailer),
654 (long) _disk_trailer_rootseek (&trailer));
656 if ( (rv = __zzip_parse_root_directory(dir->fd, &trailer, &dir->hdr0,
664 * will attach a .zip extension and tries to open it
665 * the with => open(2). This is a helper function for
666 * => zzip_dir_open, => zzip_opendir and => zzip_open.
669 __zzip_try_open(zzip_char_t* filename, int filemode,
670 zzip_strings_t* ext, zzip_plugin_io_t io)
672 auto char file[PATH_MAX];
674 zzip_size_t len = strlen (filename);
676 if (len+4 >= PATH_MAX) return -1;
677 memcpy(file, filename, len+1);
679 if (!io) io = zzip_get_default_io();
680 if (!ext) ext = zzip_get_default_ext();
682 for ( ; *ext ; ++ext)
684 strcpy (file+len, *ext);
685 fd = io->fd.open(file, filemode);
686 if (fd != -1) return fd;
692 * Opens the zip-archive (if available).
693 * the two ext_io arguments will default to use posix io and
694 * a set of default fileext that can atleast add .zip ext itself.
697 zzip_dir_open(zzip_char_t* filename, zzip_error_t* e)
699 return zzip_dir_open_ext_io (filename, e, 0, 0);
703 * this function uses explicit ext and io instead of the internal
704 * defaults. Setting these to zero is equivalent to => zzip_dir_open
707 zzip_dir_open_ext_io(zzip_char_t* filename, zzip_error_t* e,
708 zzip_strings_t* ext, zzip_plugin_io_t io)
712 if (!io) io = zzip_get_default_io();
713 if (!ext) ext = zzip_get_default_ext();
715 fd = io->fd.open(filename, O_RDONLY|O_BINARY);
717 { return zzip_dir_fdopen_ext_io(fd, e, ext, io); }
720 fd = __zzip_try_open(filename, O_RDONLY|O_BINARY, ext, io);
722 { return zzip_dir_fdopen_ext_io(fd, e, ext, io); }
725 if (e) { *e = ZZIP_DIR_OPEN; }
732 * fills the dirent-argument with the values and
733 * increments the read-pointer of the dir-argument.
735 * returns 0 if there no entry (anymore).
738 zzip_dir_read(ZZIP_DIR * dir, ZZIP_DIRENT * d )
740 if (! dir || ! dir->hdr || ! d) return 0;
742 d->d_compr = dir->hdr->d_compr;
743 d->d_csize = dir->hdr->d_csize;
744 d->st_size = dir->hdr->d_usize;
745 d->d_name = dir->hdr->d_name;
747 if (! dir->hdr->d_reclen)
750 { dir->hdr = (struct zzip_dir_hdr *)((char *)dir->hdr + dir->hdr->d_reclen); }
757 * c-file-style: "stroustrup"