]> granicus.if.org Git - zziplib/commitdiff
zzip64 support
authorGuido Draheim <guidod@gmx.de>
Sat, 14 May 2005 18:15:42 +0000 (18:15 +0000)
committerGuido Draheim <guidod@gmx.de>
Sat, 14 May 2005 18:15:42 +0000 (18:15 +0000)
 (.)

zzip/fseeko.c
zzip/memdisk.c [new file with mode: 0644]
zzip/memdisk.h [new file with mode: 0644]

index 6b48af9071deb634f46eb39618c578c5f45ff183..61a2852bd68b2aab4be636a150a5e6a1953bb71e 100644 (file)
@@ -121,11 +121,13 @@ static zzip_off_t
 zzip_entry_fread_file_header (ZZIP_ENTRY* entry, 
                             struct zzip_file_header* file_header)
 {
-    zzip_off_t offset = zzip_disk_entry_fileoffset (disk_(entry));
+    if (! entry || ! file_header) return 0;
+    ___ zzip_off_t offset = zzip_disk_entry_fileoffset (disk_(entry));
     if (0 > offset || offset >= entry->disksize) return 0;
+
     fseeko (entry->diskfile, offset, SEEK_SET);
     return (fread (file_header, sizeof(*file_header), 1, entry->diskfile)
-           ? offset+sizeof(*file_header) : 0 );
+           ? offset+sizeof(*file_header) : 0 ); ____;
 }
 
 /** helper functions for (fseeko) zip access api
@@ -162,8 +164,7 @@ zzip_entry_strdup_name(ZZIP_ENTRY* entry)
     if (! entry) return 0;
 
     ___ zzip_size_t len;
-    if ((len = zzip_disk_entry_namlen (disk_(entry))))
-    {
+    if ((len = zzip_disk_entry_namlen (disk_(entry)))) {
        char* name = malloc (len+1);
        if (! name) return 0;
        memcpy (name, entry->tail, len);
@@ -171,9 +172,8 @@ zzip_entry_strdup_name(ZZIP_ENTRY* entry)
        return name;
     }
     ___ auto struct zzip_file_header header;
-    if (zzip_entry_fread_file_header (entry, &header) &&
-       (( len = zzip_file_header_namlen(&header) )))
-    {
+    if (zzip_entry_fread_file_header (entry, &header) 
+       && ( len = zzip_file_header_namlen(&header) )) {
        char* name = malloc (len+1);
        if (! name) return 0;
        fread (name, 1, len, entry->diskfile);
@@ -187,9 +187,9 @@ zzip_entry_strdup_name(ZZIP_ENTRY* entry)
 static int
 prescan_entry(ZZIP_ENTRY* entry) 
 {
-    zzip_off_t tailsize = zzip_disk_entry_sizeof_tails (disk_(entry));
-    if (tailsize+1 > entry->tailalloc) 
-    {
+    assert (entry);
+    ___ zzip_off_t tailsize = zzip_disk_entry_sizeof_tails (disk_(entry));
+    if (tailsize+1 > entry->tailalloc) {
        char* newtail = realloc (entry->tail, tailsize+1);
        if (! newtail) return ENOMEM;
        entry->tail = newtail;
@@ -197,12 +197,13 @@ prescan_entry(ZZIP_ENTRY* entry)
     }
     fread (entry->tail, 1, tailsize, entry->diskfile);
     /* name + comment + extras */
-    return 0;
+    return 0; ____;
 }
 
 static void
 prescan_clear(ZZIP_ENTRY* entry)
 {
+    assert (entry);
     if (entry->tail) free (entry->tail);
     entry->tail = 0; entry->tailalloc = 0;
 }
@@ -255,8 +256,7 @@ zzip_entry_findfirst(FILE* disk)
     ___ zzip_off_t mapsize = disksize - mapoffs;
     if (mapoffs && mapsize < pagesize/2) { 
        mapoffs -= pagesize/2; mapsize += pagesize/2; }
-    while(1) 
-    {
+    while(1) {
        fseeko (disk, mapoffs, SEEK_SET);
        fread (buffer, 1, mapsize, disk);
        ___ char* p = buffer + mapsize - sizeof(struct zzip_disk_trailer);
@@ -266,8 +266,8 @@ zzip_entry_findfirst(FILE* disk)
            if (zzip_disk_trailer_check_magic(p)) {
                root = zzip_disk_trailer_rootseek (
                    (struct zzip_disk_trailer*)p);
-               if (root > disksize - (long) sizeof(struct zzip_disk_trailer)) 
-               {   /* first disk_entry is after the disk_trailer? can't be! */
+               if (root > disksize - (long)sizeof(struct zzip_disk_trailer)) {
+                   /* first disk_entry is after the disk_trailer? can't be! */
                    zzip_off_t rootsize = zzip_disk_trailer_rootsize (
                        (struct zzip_disk_trailer*)p);
                    if (rootsize > mapoffs) continue;
@@ -280,11 +280,11 @@ zzip_entry_findfirst(FILE* disk)
                root = zzip_disk64_trailer_rootseek (
                    (struct zzip_disk64_trailer*)p);
            } else continue;
+
            assert (0 <= root && root < mapsize);
            fseeko (disk, root, SEEK_SET);
            fread (disk_(entry), 1, sizeof(*disk_(entry)), disk);
-           if (zzip_disk_entry_check_magic(entry)) 
-           {
+           if (zzip_disk_entry_check_magic(entry)) {
                free (buffer);
                entry->headseek = root;
                entry->diskfile = disk;
@@ -321,6 +321,7 @@ zzip_entry_findnext(ZZIP_ENTRY* _zzip_restrict entry)
     ___ zzip_off_t seek = 
        entry->headseek + zzip_disk_entry_sizeto_end (disk_(entry));
     if (seek + (zzip_off_t) sizeof(*disk_(entry)) > entry->disksize) goto err;
+
     fseeko (entry->diskfile, seek, SEEK_SET);
     fread (disk_(entry), 1, sizeof(*disk_(entry)), entry->diskfile);
     entry->headseek = seek;
@@ -363,20 +364,19 @@ zzip_entry_findfile(FILE* disk, char* filename,
                    zzip_strcmp_fn_t compare)
 {
     if (! filename || ! disk) return 0;
-    entry = ! entry ? zzip_entry_findfirst (disk) 
+    entry = ( ! entry ) ? zzip_entry_findfirst (disk) 
        : zzip_entry_findnext (entry);
-
     if (! compare) compare = (zzip_strcmp_fn_t)(strcmp);
+
     for (; entry ; entry = zzip_entry_findnext (entry))
-    {
-       /* filenames within zip files are often not null-terminated! */
+    {  /* filenames within zip files are often not null-terminated! */
        char* realname = zzip_entry_strdup_name (entry);
-       if (realname && ! compare(filename, realname))
-       {
-           free (realname);
-           return entry;
+       if (! realname) continue;
+       if (! compare (filename, realname)) {
+           free (realname);    return entry;
+       } else {
+           free (realname);    continue;
        }
-       free (realname);
     }
     return 0;
 }
@@ -418,20 +418,19 @@ zzip_entry_findmatch(FILE* disk, char* filespec,
                     zzip_fnmatch_fn_t compare, int flags)
 {
     if (! filespec || ! disk) return 0;
-    entry = ! entry ? zzip_entry_findfirst (disk) 
+    entry = ( ! entry ) ? zzip_entry_findfirst (disk) 
        : zzip_entry_findnext (entry);
-
     if (! compare) compare = (zzip_fnmatch_fn_t) _zzip_fnmatch; 
+
     for (; entry ; entry = zzip_entry_findnext (entry))
-    {
-       /* filenames within zip files are often not null-terminated! */
-       char* realname = zzip_entry_strdup_name(entry);
-       if (realname && ! compare(filespec, realname, flags))
-       {
-           free (realname);
-           return entry;
+    {  /* filenames within zip files are often not null-terminated! */
+       char* realname = zzip_entry_strdup_name (entry);
+       if (! realname) continue;
+       if (! compare (filespec, realname, flags)) 
+           free (realname);    return entry;
+       } else {
+           free (realname);    continue;
        }
-       free (realname);
     }
     return 0;
 }
@@ -469,8 +468,7 @@ ZZIP_ENTRY_FILE* _zzip_new
 zzip_entry_fopen (ZZIP_ENTRY* entry, int takeover)
 {
     if (! entry) return 0;
-    if (! takeover) 
-    {
+    if (! takeover) {
        ZZIP_ENTRY* found = malloc (sizeof(*entry));
        if (! found) return 0;
        memcpy (found, entry, sizeof(*entry));   /* prescan_copy */
@@ -505,8 +503,8 @@ zzip_entry_fopen (ZZIP_ENTRY* entry, int takeover)
                                 file->entry->diskfile);
     file->dataoff += file->zlib.avail_in; ____;
 
-    if (! zzip_file_header_data_deflated (&file->header) ||
-       inflateInit2 (& file->zlib, -MAX_WBITS) != Z_OK) goto fail2;
+    if (! zzip_file_header_data_deflated (&file->header) 
+       || inflateInit2 (& file->zlib, -MAX_WBITS) != Z_OK) goto fail2;
 
     return file;
  fail2:
@@ -526,7 +524,8 @@ ZZIP_ENTRY_FILE* _zzip_new
 zzip_entry_ffile (FILE* disk, char* filename)
 {
     ZZIP_ENTRY* entry = zzip_entry_findfile (disk, filename, 0, 0);
-    if (! entry) return 0; else return zzip_entry_fopen (entry, 1);
+    if (! entry) return 0;
+    return zzip_entry_fopen (entry, 1);
 }
 
 
@@ -541,9 +540,9 @@ zzip_size_t
 zzip_entry_fread (void* ptr, zzip_size_t sized, zzip_size_t nmemb,
                  ZZIP_ENTRY_FILE* file)
 {
-     zzip_size_t size = sized*nmemb;
-    if (! file->compressed)
-    {
+    if (! file) return 0;
+    ___ zzip_size_t size = sized*nmemb;
+    if (! file->compressed) {
        if (size > file->avail) size = file->avail;
        fread (ptr, 1, size, file->entry->diskfile);
        file->dataoff += size;
@@ -554,10 +553,8 @@ zzip_entry_fread (void* ptr, zzip_size_t sized, zzip_size_t nmemb,
     file->zlib.avail_out = size;
     file->zlib.next_out = ptr;
     ___ zzip_size_t total_old = file->zlib.total_out;
-    while (1) 
-    {
-       if (! file->zlib.avail_in) 
-       {   
+    while (1) {
+       if (! file->zlib.avail_in) {   
            size = file->compressed - file->dataoff;
            if (size > sizeof(file->buffer)) size = sizeof(file->buffer);
            /* fseek (file->data + file->dataoff, file->entry->diskfile); */
@@ -578,7 +575,7 @@ zzip_entry_fread (void* ptr, zzip_size_t sized, zzip_size_t nmemb,
        ____;
        if (file->zlib.avail_out && ! file->zlib.avail_in) continue;
        return file->zlib.total_out - total_old;
-    }____;
+    }____;____;
 }
 
 /** => zzip_entry_fopen
@@ -588,6 +585,7 @@ zzip_entry_fread (void* ptr, zzip_size_t sized, zzip_size_t nmemb,
 int
 zzip_entry_fclose (ZZIP_ENTRY_FILE* file)
 {
+    if (! file) return 0;
     if (file->compressed)
        inflateEnd (& file->zlib);
     zzip_entry_free (file->entry);
diff --git a/zzip/memdisk.c b/zzip/memdisk.c
new file mode 100644 (file)
index 0000000..b6d51ab
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * The mem_disk cache will parse the central information of a zip archive
+ * and store it internally. One the one hand it allows to find files
+ * faster - no disk access is required and endian conversion is not
+ * needed. If zzip is compiled with zip extensions then it is about
+ * the only way to build maintainable code around the zip format.
+ *
+ * Note that 64bit support is almost entirely living in extension 
+ * blocks as well as different character encodings and file access
+ * control bits that are mostly platform specific.
+ *
+ * Author:
+ *    Guido Draheim <guidod@gmx.de>
+ * 
+ * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
+ *          All rights reserved,
+ *          use under the restrictions of the 
+ *          Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ */
+#define _ZZIP_MEM_DISK_PRIVATE 1
+
+#include <zzip/lib.h>                                  /* archive handling */
+#include <zzip/file.h>
+#include <zzip/format.h>
+#include <zzip/fetch.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <zzip/mmapped.h>
+#include <zzip/memdisk.h>
+
+#define ___ {
+#define ____ }
+
+static const char* error[] = {
+    "Ok",
+#   define _zzip_mem_disk_open_fail 1
+    "zzip_mem_disk_open: zzip_disk_open did fail",
+#   define _zzip_mem_disk_fdopen_fail 2
+    "zzip_mem_disk_fdopen: zzip_disk_mmap did fail"
+};
+
+struct _zzip_mem_disk_entry {
+    struct _zzip_mem_disk_entry* zz_next;
+    char* zz_name;
+    char* zz_data;
+    int zz_flags;
+    int zz_compr;
+    long zz_crc32;
+    zzip_off_t zz_csize;
+    zzip_off_t zz_usize;
+    zzip_off_t zz_offset;
+    int zz_diskstart;
+    int zz_filetype;
+    char* zz_comment;
+    size_t zz_extcount;
+    struct _zzip_mem_disk_extra* zz_extras;
+};
+
+struct _zzip_mem_disk_extra {
+    int   zz_datatype;
+    int   zz_datasize;
+    char* zz_data;
+};
+
+static ZZIP_MEM_DISK_ENTRY* _zzip_new
+zzip_mem_disk_entry_new(ZZIP_DISK* disk, ZZIP_DISK_ENTRY* entry);
+static void
+zzip_mem_disk_entry_free(ZZIP_MEM_DISK_ENTRY* _zzip_restrict item);
+
+
+
+/** create new diskdir handle. 
+ *  wraps underlying zzip_disk_open. */
+ZZIP_MEM_DISK* _zzip_new
+zzip_mem_disk_open(char* filename)
+{
+    ZZIP_DISK* disk = zzip_disk_open(filename);
+    if (! disk) { perror(error[_zzip_mem_disk_open_fail]); return 0; }
+    ___ ZZIP_MEM_DISK* dir = calloc(1, sizeof(*dir)); 
+    zzip_mem_disk_load(dir, disk);
+    return dir; ____;
+}
+
+/** create new diskdir handle. 
+ *  wraps underlying zzip_disk_open. */
+ZZIP_MEM_DISK* _zzip_new
+zzip_mem_disk_fdopen(int fd)
+{
+    ZZIP_DISK* disk = zzip_disk_mmap(fd);
+    if (! disk) { perror(error[_zzip_mem_disk_fdopen_fail]); return 0; }
+    ___ ZZIP_MEM_DISK* dir = calloc(1, sizeof(*dir)); 
+    zzip_mem_disk_load(dir, disk);
+    return dir; ____;
+}
+
+/** parse central dir.
+ *  creates an internal copy of each entry converted to the local platform.
+ */
+int
+zzip_mem_disk_load(ZZIP_MEM_DISK* dir, ZZIP_DISK* disk)
+{
+    if (dir->list) zzip_mem_disk_unload(dir);
+    ___ struct zzip_disk_entry* entry = zzip_disk_findfirst(disk);
+    for (; entry ; entry = zzip_disk_findnext(disk, entry)) {
+       ZZIP_MEM_DISK_ENTRY* item = zzip_mem_disk_entry_new(disk, entry);
+       if (dir->last) { dir->last->zz_next = item; }
+       else { dir->list = item; }; dir->last = item;
+    } ____;
+    dir->disk = disk;
+    return 0;
+}
+
+/** convert a zip disk entry to internal format.
+ * creates a new item parsing the information out of the various places
+ * in the zip archive. This is a good place to extend functionality if
+ * you have a project with extra requirements as you can push more bits
+ * right into the diskdir_entry for later usage in higher layers.
+ */
+ZZIP_MEM_DISK_ENTRY* _zzip_new
+zzip_mem_disk_entry_new(ZZIP_DISK* disk, ZZIP_DISK_ENTRY* entry) 
+{
+    ZZIP_MEM_DISK_ENTRY* item = calloc(1, sizeof(*item));
+    struct zzip_file_header* header = 
+       zzip_disk_entry_to_file_header(disk, entry);
+    /*  there is a number of duplicated information in the file header
+     *  or the disk entry block. Theoretically some part may be missing
+     *  that exists in the other, so each and every item would need to
+     *  be checked. However, we assume that the "always-exists" fields
+     *  do either (a) exist both and have the same value or (b) the bits
+     *  in the disk entry are correct. Only the variable fields are 
+     *  checked in both places: file name, file comment, extra blocks.
+     *  From mmapped.c we do already have two helper functions for that:
+     */
+    item->zz_comment =   zzip_disk_entry_strdup_comment(disk, entry);
+    item->zz_name =      zzip_disk_entry_strdup_name(disk, entry);
+    item->zz_data =      zzip_file_header_to_data(header);
+    item->zz_flags =     zzip_disk_entry_get_flags(entry);
+    item->zz_compr =     zzip_disk_entry_get_compr(entry);
+    item->zz_crc32 =     zzip_disk_entry_get_crc32(entry);
+    item->zz_csize =     zzip_disk_entry_get_csize(entry);
+    item->zz_usize =     zzip_disk_entry_get_usize(entry);
+    item->zz_diskstart = zzip_disk_entry_get_diskstart(entry);
+    item->zz_filetype =  zzip_disk_entry_get_filetype(entry);
+
+    { /* scanning the extra blocks and building a fast-access table. */
+       size_t count = 0; struct _zzip_mem_disk_extra* cache;
+       int   len = zzip_file_header_get_extras(header);
+       char* extras = zzip_file_header_to_extras(header);
+       while (len > 0) {
+           struct zzip_extra_block* ext = (struct zzip_extra_block*) extras;
+           int size = zzip_extra_block_sizeto_end(ext);
+           len -= size; extras += size; count ++;
+       }
+       len = zzip_disk_entry_get_extras(entry);
+       extras = zzip_disk_entry_to_extras(entry);
+       while (len > 0) {
+           struct zzip_extra_block* ext = (struct zzip_extra_block*) extras;
+           int size = zzip_extra_block_sizeto_end(ext);
+           len -= size; extras += size; count ++;
+       }
+       cache = calloc(count, sizeof(struct _zzip_mem_disk_extra));
+       if (item->zz_extras) free(item->zz_extras);
+       item->zz_extras = cache;
+       item->zz_extcount = count;
+       /* ... */
+       count = 0;
+       len = zzip_file_header_get_extras(header);
+       extras = zzip_file_header_to_extras(header);
+       while (len > 0) {
+           struct zzip_extra_block* ext = (struct zzip_extra_block*) extras;
+           cache[count].zz_data = extras;
+           cache[count].zz_datatype = zzip_extra_block_get_datatype(ext);
+           cache[count].zz_datasize = zzip_extra_block_get_datasize(ext);
+           ___ register int size = zzip_extra_block_sizeto_end(ext);
+           len -= size; extras += size; count ++; ____;
+       }
+       len = zzip_disk_entry_get_extras(entry);
+       extras = zzip_disk_entry_to_extras(entry);
+       while (len > 0) {
+           struct zzip_extra_block* ext = (struct zzip_extra_block*) extras;
+           cache[count].zz_data = extras;
+           cache[count].zz_datatype = zzip_extra_block_get_datatype(ext);
+           cache[count].zz_datasize = zzip_extra_block_get_datasize(ext);
+           ___ register int size = zzip_extra_block_sizeto_end(ext);
+           len -= size; extras += size; count ++; ____;
+       }
+    }
+
+    { /* scanning the extra blocks for platform specific extensions. */
+       register size_t count;
+       for (count = 0; count < item->zz_extcount; count++) {
+           /* "http://www.pkware.com/company/standards/appnote/" */
+           switch (item->zz_extras[count].zz_datatype) {
+           case 0x0001: { /* ZIP64 extended information extra field */
+               struct {
+                   char z_datatype[2]; /* Tag for this "extra" block type */
+                   char z_datasize[2]; /* Size of this "extra" block */
+                   char z_usize[8]; /* Original uncompressed file size */
+                   char z_csize[8]; /* Size of compressed data */
+                   char z_offset[8]; /* Offset of local header record */
+                   char z_diskstart[4]; /* Number of the disk for file start*/
+               } *block = (void*) item->zz_extras[count].zz_data;
+               item->zz_usize  =    __zzip_get64(block->z_usize);
+               item->zz_csize  =    __zzip_get64(block->z_csize);
+               item->zz_offset =    __zzip_get64(block->z_offset);
+               item->zz_diskstart = __zzip_get32(block->z_diskstart);
+           } break;
+           case 0x0007: /* AV Info */
+           case 0x0008: /* Reserved for future Unicode file name data (PFS) */
+           case 0x0009: /* OS/2 */
+           case 0x000a: /* NTFS */
+           case 0x000c: /* OpenVMS */
+           case 0x000d: /* Unix */
+           case 0x000e: /* Reserved for file stream and fork descriptors */
+           case 0x000f: /* Patch Descriptor */
+           case 0x0014: /* PKCS#7 Store for X.509 Certificates */
+           case 0x0015: /* X.509 Certificate ID and Signature for file */
+           case 0x0016: /* X.509 Certificate ID for Central Directory */
+           case 0x0017: /* Strong Encryption Header */
+           case 0x0018: /* Record Management Controls */
+           case 0x0019: /* PKCS#7 Encryption Recipient Certificate List */
+           case 0x0065: /* IBM S/390, AS/400 attributes - uncompressed */
+           case 0x0066: /* Reserved for IBM S/390, AS/400 attr - compressed */
+           case 0x07c8: /* Macintosh */
+           case 0x2605: /* ZipIt Macintosh */
+           case 0x2705: /* ZipIt Macintosh 1.3.5+ */
+           case 0x2805: /* ZipIt Macintosh 1.3.5+ */
+           case 0x334d: /* Info-ZIP Macintosh */
+           case 0x4341: /* Acorn/SparkFS  */
+           case 0x4453: /* Windows NT security descriptor (binary ACL) */
+           case 0x4704: /* VM/CMS */
+           case 0x470f: /* MVS */
+           case 0x4b46: /* FWKCS MD5 (see below) */
+           case 0x4c41: /* OS/2 access control list (text ACL) */
+           case 0x4d49: /* Info-ZIP OpenVMS */
+           case 0x4f4c: /* Xceed original location extra field */
+           case 0x5356: /* AOS/VS (ACL) */
+           case 0x5455: /* extended timestamp */
+           case 0x554e: /* Xceed unicode extra field */
+           case 0x5855: /* Info-ZIP Unix (original, also OS/2, NT, etc) */
+           case 0x6542: /* BeOS/BeBox */
+           case 0x756e: /* ASi Unix */
+           case 0x7855: /* Info-ZIP Unix (new) */
+           case 0xfd4a: /* SMS/QDOS */
+               break;
+           }
+       }
+    }
+    return item;
+}
+    
+void
+zzip_mem_disk_entry_free(ZZIP_MEM_DISK_ENTRY* _zzip_restrict item) 
+{
+    if (item) {
+       if (item->zz_extras) free(item->zz_extras);
+       free (item);
+    }
+}
+
+void
+zzip_mem_disk_unload(ZZIP_MEM_DISK* dir)
+{
+    ZZIP_MEM_DISK_ENTRY* item = dir->list;
+    while (item) {
+       ZZIP_MEM_DISK_ENTRY* next = item->zz_next;
+       zzip_mem_disk_entry_free(item); item = next;
+    }
+    dir->list = dir->last = 0; dir->disk = 0;
+}
+
+void
+zzip_mem_disk_close(ZZIP_MEM_DISK* _zzip_restrict dir) 
+{
+    if (dir) {
+       zzip_mem_disk_unload (dir);
+       zzip_disk_close(dir->disk);
+       free (dir);
+    }
+}
diff --git a/zzip/memdisk.h b/zzip/memdisk.h
new file mode 100644 (file)
index 0000000..18c3247
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef __ZZIP_MEMDISK_H
+#define __ZZIP_MEMDISK_H
+
+#include <zzip/mmapped.h>
+
+typedef struct _zzip_mem_disk ZZIP_MEM_DISK;
+typedef struct _zzip_mem_disk_entry ZZIP_MEM_DISK_ENTRY;
+
+struct _zzip_mem_disk {
+    ZZIP_DISK* disk;
+#  ifdef _ZZIP_MEM_DISK_PRIVATE
+    ZZIP_MEM_DISK_ENTRY* list;
+    ZZIP_MEM_DISK_ENTRY* last;
+#  endif
+};
+
+#ifndef zzip_mem_disk_extern
+#define zzip_mem_disk_extern
+#endif
+
+zzip_mem_disk_extern ZZIP_MEM_DISK* _zzip_new
+zzip_mem_disk_open (char* filename);
+zzip_mem_disk_extern ZZIP_MEM_DISK* _zzip_new
+zzip_mem_disk_fdopen (int fd);
+zzip_mem_disk_extern void 
+zzip_mem_disk_close (ZZIP_MEM_DISK* _zzip_restrict dir);
+
+zzip_mem_disk_extern int 
+zzip_mem_disk_load (ZZIP_MEM_DISK* dir, ZZIP_DISK* disk);
+zzip_mem_disk_extern void 
+zzip_mem_disk_unload (ZZIP_MEM_DISK* dir);
+
+#ifdef USE_INLINE
+_zzip_inline ZZIP_DISK_ENTRY*
+zzip_mem_disk_findfirst(ZZIP_MEM_DISK* dir) {
+    return zzip_disk_findfirst(dir->disk); }
+_zzip_inline ZZIP_DISK_ENTRY*
+zzip_mem_disk_findnext(ZZIP_MEM_DISK* dir, ZZIP_DISK_ENTRY* entry) {
+    return zzip_mem_disk_findnext(dir->disk, entry);
+}
+#else
+#define zzip_mem_disk_findfirst(__dir) \
+             zzip_disk_findfirst((__dir)->disk)
+#define zzip_mem_disk_findnext(__dir,__entry) \
+            zzip_disk_findnext((__dir)->disk,(__entry))
+#endif
+
+#ifdef USE_INLINE
+_zzip_inline char* _zzip_new
+zzip_mem_disk_entry_strdup_name(ZZIP_MEM_DISK* dir, 
+                                ZZIP_DISK_ENTRY* entry) {
+    return zzip_disk_entry_strdup_name(dir->disk, entry); }
+_zzip_inline struct zzip_file_header*
+zzip_mem_disk_entry_to_file_header(ZZIP_MEM_DISK* dir, 
+                                  ZZIP_DISK_ENTRY* entry) {
+    return zzip_disk_entry_to_file_header(dir->disk, entry); }
+_zzip_inline char*
+zzip_mem_disk_entry_to_data(ZZIP_MEM_DISK* dir, ZZIP_DISK_ENTRY* entry) {
+    return zzip_disk_entry_to_data(dir->disk, entry); }
+#else
+#define zzip_mem_disk_entry_strdup_name(__dir,__entry) \
+            zzip_disk_entry_strdup_name((__dir)->disk,(__entry))
+#define zzip_mem_disk_entry_to_file_header(__dir,__entry) \
+            zzip_disk_entry_to_file_header((__dir)->disk,(__entry))
+#define zzip_mem_disk_entry_to_data(__dir,__entry) \
+            zzip_disk_entry_to_data((__dir)->disk,(__entry))
+#endif
+
+#ifdef USE_INLINE
+_zzip_inline ZZIP_DISK_ENTRY*
+zzip_mem_disk_findfile(ZZIP_MEM_DISK* dir, 
+                       char* filename, ZZIP_DISK_ENTRY* after,
+                      zzip_strcmp_fn_t compare) {
+    return zzip_disk_findfile(dir->disk, filename, after, compare); }
+_zzip_inline ZZIP_DISK_ENTRY*
+zzip_mem_disk_findmatch(ZZIP_MEM_DISK* dir, 
+                        char* filespec, ZZIP_DISK_ENTRY* after,
+                       zzip_fnmatch_fn_t compare, int flags) {
+    return zzip_disk_findmatch(dir->disk, filespec, after, compare, flags); }
+#else
+#define zzip_mem_disk_findfile(__dir,__name,__after,__compare) \
+            zzip_disk_findfile((__dir)->disk,(__name),(__after), \
+                                                    (__compare))
+#define zzip_mem_disk_findmatch(__dir,__spec,__after,__compare,__flags) \
+            zzip_disk_findmatch((__dir)->disk,(__spec),(__after), \
+                                           (__compare),(__flags))
+#endif
+
+#ifdef USE_INLINE
+_zzip_inline ZZIP_DISK_FILE* _zzip_new
+zzip_mem_disk_entry_fopen (ZZIP_MEM_DISK* dir, ZZIP_DISK_ENTRY* entry) {
+    return zzip_disk_entry_fopen(dir->disk, entry); }
+_zzip_inline ZZIP_DISK_FILE* _zzip_new
+zzip_mem_disk_fopen (ZZIP_MEM_DISK* dir, char* filename) {
+    return zzip_disk_fopen(dir->disk, filename); }
+_zzip_inline _zzip_size_t
+zzip_mem_disk_fread (void* ptr, _zzip_size_t size, _zzip_size_t nmemb,
+                     ZZIP_DISK_FILE* file) {
+    return zzip_disk_fread(ptr, size, nmemb, file); }
+_zzip_inline int
+zzip_mem_disk_fclose (ZZIP_DISK_FILE* file) {
+    return zzip_disk_fclose(file); }
+_zzip_inline int
+zzip_mem_disk_feof (ZZIP_DISK_FILE* file) {
+    return zzip_disk_feof(file); }
+#else
+#define zzip_mem_disk_entry_fopen(__dir,__entry) \
+            zzip_disk_entry_fopen((__dir)->disk,(__entry))
+
+#define zzip_mem_disk_fopen(__dir,__name) \
+            zzip_disk_fopen((__dir)->disk,(__name))
+
+#define zzip_mem_disk_fread(__ptr,__size,__nmemb,__file) \
+            zzip_disk_fread((__ptr),(__size),(__nmemb),(__file))
+#define zzip_mem_disk_fclose(__file) \
+        zzip_disk_fclose((__file))
+#define zzip_mem_disk_feof(__file) \
+            zzip_disk_feof((__file))
+#endif
+
+#endif