misc/libphysfs/archiver_zip.c
branchqmlfrontend
changeset 12855 1b2b84315d27
parent 12452 e18cfe90e4e2
child 13393 ae5d6448c5be
equal deleted inserted replaced
11843:01f88c3b7b66 12855:1b2b84315d27
    13 #if PHYSFS_SUPPORTS_ZIP
    13 #if PHYSFS_SUPPORTS_ZIP
    14 
    14 
    15 #include <errno.h>
    15 #include <errno.h>
    16 #include <time.h>
    16 #include <time.h>
    17 
    17 
    18 #define USE_MINIZ 1
       
    19 #if USE_MINIZ
       
    20 #include "physfs_miniz.h"
    18 #include "physfs_miniz.h"
    21 #else
       
    22 #include <zlib.h>
       
    23 #endif
       
    24 
    19 
    25 /*
    20 /*
    26  * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
    21  * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
    27  *  and is freed when you close the file; compressed data is read into
    22  *  and is freed when you close the file; compressed data is read into
    28  *  this buffer, and then is decompressed into the buffer passed to
    23  *  this buffer, and then is decompressed into the buffer passed to
    49 {
    44 {
    50     ZIP_UNRESOLVED_FILE,
    45     ZIP_UNRESOLVED_FILE,
    51     ZIP_UNRESOLVED_SYMLINK,
    46     ZIP_UNRESOLVED_SYMLINK,
    52     ZIP_RESOLVING,
    47     ZIP_RESOLVING,
    53     ZIP_RESOLVED,
    48     ZIP_RESOLVED,
       
    49     ZIP_DIRECTORY,
    54     ZIP_BROKEN_FILE,
    50     ZIP_BROKEN_FILE,
    55     ZIP_BROKEN_SYMLINK
    51     ZIP_BROKEN_SYMLINK
    56 } ZipResolveType;
    52 } ZipResolveType;
    57 
    53 
    58 
    54 
    65     struct _ZIPentry *symlink;          /* NULL or file we symlink to     */
    61     struct _ZIPentry *symlink;          /* NULL or file we symlink to     */
    66     ZipResolveType resolved;            /* Have we resolved file/symlink? */
    62     ZipResolveType resolved;            /* Have we resolved file/symlink? */
    67     PHYSFS_uint64 offset;               /* offset of data in archive      */
    63     PHYSFS_uint64 offset;               /* offset of data in archive      */
    68     PHYSFS_uint16 version;              /* version made by                */
    64     PHYSFS_uint16 version;              /* version made by                */
    69     PHYSFS_uint16 version_needed;       /* version needed to extract      */
    65     PHYSFS_uint16 version_needed;       /* version needed to extract      */
       
    66     PHYSFS_uint16 general_bits;         /* general purpose bits           */
    70     PHYSFS_uint16 compression_method;   /* compression method             */
    67     PHYSFS_uint16 compression_method;   /* compression method             */
    71     PHYSFS_uint32 crc;                  /* crc-32                         */
    68     PHYSFS_uint32 crc;                  /* crc-32                         */
    72     PHYSFS_uint64 compressed_size;      /* compressed size                */
    69     PHYSFS_uint64 compressed_size;      /* compressed size                */
    73     PHYSFS_uint64 uncompressed_size;    /* uncompressed size              */
    70     PHYSFS_uint64 uncompressed_size;    /* uncompressed size              */
    74     PHYSFS_sint64 last_mod_time;        /* last file mod time             */
    71     PHYSFS_sint64 last_mod_time;        /* last file mod time             */
       
    72     PHYSFS_uint32 dos_mod_time;         /* original MS-DOS style mod time */
       
    73     struct _ZIPentry *hashnext;         /* next item in this hash bucket  */
       
    74     struct _ZIPentry *children;         /* linked list of kids, if dir    */
       
    75     struct _ZIPentry *sibling;          /* next item in same dir          */
    75 } ZIPentry;
    76 } ZIPentry;
    76 
    77 
    77 /*
    78 /*
    78  * One ZIPinfo is kept for each open ZIP archive.
    79  * One ZIPinfo is kept for each open ZIP archive.
    79  */
    80  */
    80 typedef struct
    81 typedef struct
    81 {
    82 {
    82     PHYSFS_Io *io;
    83     PHYSFS_Io *io;            /* the i/o interface for this archive.    */
    83     int zip64;                /* non-zero if this is a Zip64 archive. */
    84     ZIPentry root;            /* root of directory tree.                */
    84     PHYSFS_uint64 entryCount; /* Number of files in ZIP.              */
    85     ZIPentry **hash;          /* all entries hashed for fast lookup.    */
    85     ZIPentry *entries;        /* info on all files in ZIP.            */
    86     size_t hashBuckets;       /* number of buckets in hash.             */
       
    87     int zip64;                /* non-zero if this is a Zip64 archive.   */
       
    88     int has_crypto;           /* non-zero if any entry uses encryption. */
    86 } ZIPinfo;
    89 } ZIPinfo;
    87 
    90 
    88 /*
    91 /*
    89  * One ZIPfileinfo is kept for each open file in a ZIP archive.
    92  * One ZIPfileinfo is kept for each open file in a ZIP archive.
    90  */
    93  */
    93     ZIPentry *entry;                      /* Info on file.              */
    96     ZIPentry *entry;                      /* Info on file.              */
    94     PHYSFS_Io *io;                        /* physical file handle.      */
    97     PHYSFS_Io *io;                        /* physical file handle.      */
    95     PHYSFS_uint32 compressed_position;    /* offset in compressed data. */
    98     PHYSFS_uint32 compressed_position;    /* offset in compressed data. */
    96     PHYSFS_uint32 uncompressed_position;  /* tell() position.           */
    99     PHYSFS_uint32 uncompressed_position;  /* tell() position.           */
    97     PHYSFS_uint8 *buffer;                 /* decompression buffer.      */
   100     PHYSFS_uint8 *buffer;                 /* decompression buffer.      */
       
   101     PHYSFS_uint32 crypto_keys[3];         /* for "traditional" crypto.  */
       
   102     PHYSFS_uint32 initial_crypto_keys[3]; /* for "traditional" crypto.  */
    98     z_stream stream;                      /* zlib stream state.         */
   103     z_stream stream;                      /* zlib stream state.         */
    99 } ZIPfileinfo;
   104 } ZIPfileinfo;
   100 
   105 
   101 
   106 
   102 /* Magic numbers... */
   107 /* Magic numbers... */
   113 
   118 
   114 
   119 
   115 #define UNIX_FILETYPE_MASK    0170000
   120 #define UNIX_FILETYPE_MASK    0170000
   116 #define UNIX_FILETYPE_SYMLINK 0120000
   121 #define UNIX_FILETYPE_SYMLINK 0120000
   117 
   122 
       
   123 #define ZIP_GENERAL_BITS_TRADITIONAL_CRYPTO   (1 << 0)
       
   124 #define ZIP_GENERAL_BITS_IGNORE_LOCAL_HEADER  (1 << 3)
       
   125 
       
   126 /* support for "traditional" PKWARE encryption. */
       
   127 static int zip_entry_is_tradional_crypto(const ZIPentry *entry)
       
   128 {
       
   129     return (entry->general_bits & ZIP_GENERAL_BITS_TRADITIONAL_CRYPTO) != 0;
       
   130 } /* zip_entry_is_traditional_crypto */
       
   131 
       
   132 static int zip_entry_ignore_local_header(const ZIPentry *entry)
       
   133 {
       
   134     return (entry->general_bits & ZIP_GENERAL_BITS_IGNORE_LOCAL_HEADER) != 0;
       
   135 } /* zip_entry_is_traditional_crypto */
       
   136 
       
   137 static PHYSFS_uint32 zip_crypto_crc32(const PHYSFS_uint32 crc, const PHYSFS_uint8 val)
       
   138 {
       
   139     int i;
       
   140     PHYSFS_uint32 xorval = (crc ^ ((PHYSFS_uint32) val)) & 0xFF;
       
   141     for (i = 0; i < 8; i++)
       
   142         xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1));
       
   143     return xorval ^ (crc >> 8);
       
   144 } /* zip_crc32 */
       
   145 
       
   146 static void zip_update_crypto_keys(PHYSFS_uint32 *keys, const PHYSFS_uint8 val)
       
   147 {
       
   148     keys[0] = zip_crypto_crc32(keys[0], val);
       
   149     keys[1] = keys[1] + (keys[0] & 0x000000FF);
       
   150     keys[1] = (keys[1] * 134775813) + 1;
       
   151     keys[2] = zip_crypto_crc32(keys[2], (PHYSFS_uint8) ((keys[1] >> 24) & 0xFF));
       
   152 } /* zip_update_crypto_keys */
       
   153 
       
   154 static PHYSFS_uint8 zip_decrypt_byte(const PHYSFS_uint32 *keys)
       
   155 {
       
   156     const PHYSFS_uint16 tmp = keys[2] | 2;
       
   157     return (PHYSFS_uint8) ((tmp * (tmp ^ 1)) >> 8);
       
   158 } /* zip_decrypt_byte */
       
   159 
       
   160 static PHYSFS_sint64 zip_read_decrypt(ZIPfileinfo *finfo, void *buf, PHYSFS_uint64 len)
       
   161 {
       
   162     PHYSFS_Io *io = finfo->io;
       
   163     const PHYSFS_sint64 br = io->read(io, buf, len);
       
   164 
       
   165     /* Decompression the new data if necessary. */
       
   166     if (zip_entry_is_tradional_crypto(finfo->entry) && (br > 0))
       
   167     {
       
   168         PHYSFS_uint32 *keys = finfo->crypto_keys;
       
   169         PHYSFS_uint8 *ptr = (PHYSFS_uint8 *) buf;
       
   170         PHYSFS_sint64 i;
       
   171         for (i = 0; i < br; i++, ptr++)
       
   172         {
       
   173             const PHYSFS_uint8 ch = *ptr ^ zip_decrypt_byte(keys);
       
   174             zip_update_crypto_keys(keys, ch);
       
   175             *ptr = ch;
       
   176         } /* for */
       
   177     } /* if  */
       
   178 
       
   179     return br;
       
   180 } /* zip_read_decrypt */
       
   181 
       
   182 static int zip_prep_crypto_keys(ZIPfileinfo *finfo, const PHYSFS_uint8 *crypto_header, const PHYSFS_uint8 *password)
       
   183 {
       
   184     /* It doesn't appear to be documented in PKWare's APPNOTE.TXT, but you
       
   185        need to use a different byte in the header to verify the password
       
   186        if general purpose bit 3 is set. Discovered this from Info-Zip.
       
   187        That's what the (verifier) value is doing, below. */
       
   188 
       
   189     PHYSFS_uint32 *keys = finfo->crypto_keys;
       
   190     const ZIPentry *entry = finfo->entry;
       
   191     const int usedate = zip_entry_ignore_local_header(entry);
       
   192     const PHYSFS_uint8 verifier = (PHYSFS_uint8) ((usedate ? (entry->dos_mod_time >> 8) : (entry->crc >> 24)) & 0xFF);
       
   193     PHYSFS_uint8 finalbyte = 0;
       
   194     int i = 0;
       
   195 
       
   196     /* initialize vector with defaults, then password, then header. */
       
   197     keys[0] = 305419896;
       
   198     keys[1] = 591751049;
       
   199     keys[2] = 878082192;
       
   200 
       
   201     while (*password)
       
   202         zip_update_crypto_keys(keys, *(password++));
       
   203 
       
   204     for (i = 0; i < 12; i++)
       
   205     {
       
   206         const PHYSFS_uint8 c = crypto_header[i] ^ zip_decrypt_byte(keys);
       
   207         zip_update_crypto_keys(keys, c);
       
   208         finalbyte = c;
       
   209     } /* for */
       
   210 
       
   211     /* you have a 1/256 chance of passing this test incorrectly. :/ */
       
   212     if (finalbyte != verifier)
       
   213         BAIL_MACRO(PHYSFS_ERR_BAD_PASSWORD, 0);
       
   214 
       
   215     /* save the initial vector for seeking purposes. Not secure!! */
       
   216     memcpy(finfo->initial_crypto_keys, finfo->crypto_keys, 12);
       
   217     return 1;
       
   218 } /* zip_prep_crypto_keys */
       
   219 
   118 
   220 
   119 /*
   221 /*
   120  * Bridge physfs allocation functions to zlib's format...
   222  * Bridge physfs allocation functions to zlib's format...
   121  */
   223  */
   122 static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
   224 static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
   161 /*
   263 /*
   162  * Wrap all zlib calls in this, so the physfs error state is set appropriately.
   264  * Wrap all zlib calls in this, so the physfs error state is set appropriately.
   163  */
   265  */
   164 static int zlib_err(const int rc)
   266 static int zlib_err(const int rc)
   165 {
   267 {
   166     __PHYSFS_setError(zlib_error_code(rc));
   268     PHYSFS_setErrorCode(zlib_error_code(rc));
   167     return rc;
   269     return rc;
   168 } /* zlib_err */
   270 } /* zlib_err */
   169 
   271 
       
   272 /*
       
   273  * Hash a string for lookup an a ZIPinfo hashtable.
       
   274  */
       
   275 static inline PHYSFS_uint32 zip_hash_string(const ZIPinfo *info, const char *s)
       
   276 {
       
   277     return __PHYSFS_hashString(s, strlen(s)) % info->hashBuckets;
       
   278 } /* zip_hash_string */
   170 
   279 
   171 /*
   280 /*
   172  * Read an unsigned 64-bit int and swap to native byte order.
   281  * Read an unsigned 64-bit int and swap to native byte order.
   173  */
   282  */
   174 static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
   283 static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
   204 
   313 
   205 
   314 
   206 static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
   315 static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
   207 {
   316 {
   208     ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
   317     ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
   209     PHYSFS_Io *io = finfo->io;
       
   210     ZIPentry *entry = finfo->entry;
   318     ZIPentry *entry = finfo->entry;
   211     PHYSFS_sint64 retval = 0;
   319     PHYSFS_sint64 retval = 0;
   212     PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
   320     PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
   213     PHYSFS_sint64 avail = entry->uncompressed_size -
   321     PHYSFS_sint64 avail = entry->uncompressed_size -
   214                           finfo->uncompressed_position;
   322                           finfo->uncompressed_position;
   217         maxread = avail;
   325         maxread = avail;
   218 
   326 
   219     BAIL_IF_MACRO(maxread == 0, ERRPASS, 0);    /* quick rejection. */
   327     BAIL_IF_MACRO(maxread == 0, ERRPASS, 0);    /* quick rejection. */
   220 
   328 
   221     if (entry->compression_method == COMPMETH_NONE)
   329     if (entry->compression_method == COMPMETH_NONE)
   222         retval = io->read(io, buf, maxread);
   330         retval = zip_read_decrypt(finfo, buf, maxread);
   223     else
   331     else
   224     {
   332     {
   225         finfo->stream.next_out = buf;
   333         finfo->stream.next_out = buf;
   226         finfo->stream.avail_out = (uInt) maxread;
   334         finfo->stream.avail_out = (uInt) maxread;
   227 
   335 
   238                 if (br > 0)
   346                 if (br > 0)
   239                 {
   347                 {
   240                     if (br > ZIP_READBUFSIZE)
   348                     if (br > ZIP_READBUFSIZE)
   241                         br = ZIP_READBUFSIZE;
   349                         br = ZIP_READBUFSIZE;
   242 
   350 
   243                     br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
   351                     br = zip_read_decrypt(finfo, finfo->buffer, (PHYSFS_uint64) br);
   244                     if (br <= 0)
   352                     if (br <= 0)
   245                         break;
   353                         break;
   246 
   354 
   247                     finfo->compressed_position += (PHYSFS_uint32) br;
   355                     finfo->compressed_position += (PHYSFS_uint32) br;
   248                     finfo->stream.next_in = finfo->buffer;
   356                     finfo->stream.next_in = finfo->buffer;
   280 static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
   388 static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
   281 {
   389 {
   282     ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
   390     ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
   283     ZIPentry *entry = finfo->entry;
   391     ZIPentry *entry = finfo->entry;
   284     PHYSFS_Io *io = finfo->io;
   392     PHYSFS_Io *io = finfo->io;
       
   393     const int encrypted = zip_entry_is_tradional_crypto(entry);
   285 
   394 
   286     BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
   395     BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
   287 
   396 
   288     if (entry->compression_method == COMPMETH_NONE)
   397     if (!encrypted && (entry->compression_method == COMPMETH_NONE))
   289     {
   398     {
   290         const PHYSFS_sint64 newpos = offset + entry->offset;
   399         PHYSFS_sint64 newpos = offset + entry->offset;
   291         BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
   400         BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
   292         finfo->uncompressed_position = (PHYSFS_uint32) offset;
   401         finfo->uncompressed_position = (PHYSFS_uint32) offset;
   293     } /* if */
   402     } /* if */
   294 
   403 
   295     else
   404     else
   306             z_stream str;
   415             z_stream str;
   307             initializeZStream(&str);
   416             initializeZStream(&str);
   308             if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
   417             if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
   309                 return 0;
   418                 return 0;
   310 
   419 
   311             if (!io->seek(io, entry->offset))
   420             if (!io->seek(io, entry->offset + (encrypted ? 12 : 0)))
   312                 return 0;
   421                 return 0;
   313 
   422 
   314             inflateEnd(&finfo->stream);
   423             inflateEnd(&finfo->stream);
   315             memcpy(&finfo->stream, &str, sizeof (z_stream));
   424             memcpy(&finfo->stream, &str, sizeof (z_stream));
   316             finfo->uncompressed_position = finfo->compressed_position = 0;
   425             finfo->uncompressed_position = finfo->compressed_position = 0;
       
   426 
       
   427             if (encrypted)
       
   428                 memcpy(finfo->crypto_keys, finfo->initial_crypto_keys, 12);
   317         } /* if */
   429         } /* if */
   318 
   430 
   319         while (finfo->uncompressed_position != offset)
   431         while (finfo->uncompressed_position != offset)
   320         {
   432         {
   321             PHYSFS_uint8 buf[512];
   433             PHYSFS_uint8 buf[512];
   432     PHYSFS_sint32 maxread;
   544     PHYSFS_sint32 maxread;
   433     PHYSFS_sint32 totalread = 0;
   545     PHYSFS_sint32 totalread = 0;
   434     int found = 0;
   546     int found = 0;
   435 
   547 
   436     filelen = io->length(io);
   548     filelen = io->length(io);
   437     BAIL_IF_MACRO(filelen == -1, ERRPASS, 0);
   549     BAIL_IF_MACRO(filelen == -1, ERRPASS, -1);
   438 
   550 
   439     /*
   551     /*
   440      * Jump to the end of the file and start reading backwards.
   552      * Jump to the end of the file and start reading backwards.
   441      *  The last thing in the file is the zipfile comment, which is variable
   553      *  The last thing in the file is the zipfile comment, which is variable
   442      *  length, and the field that specifies its size is before it in the
   554      *  length, and the field that specifies its size is before it in the
   486                 (buf[i + 1] == 0x4B) &&
   598                 (buf[i + 1] == 0x4B) &&
   487                 (buf[i + 2] == 0x05) &&
   599                 (buf[i + 2] == 0x05) &&
   488                 (buf[i + 3] == 0x06) )
   600                 (buf[i + 3] == 0x06) )
   489             {
   601             {
   490                 found = 1;  /* that's the signature! */
   602                 found = 1;  /* that's the signature! */
   491                 break;
   603                 break;  
   492             } /* if */
   604             } /* if */
   493         } /* for */
   605         } /* for */
   494 
   606 
   495         if (found)
   607         if (found)
   496             break;
   608             break;
   534 
   646 
   535     return retval;
   647     return retval;
   536 } /* isZip */
   648 } /* isZip */
   537 
   649 
   538 
   650 
   539 static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
   651 /* Find the ZIPentry for a path in platform-independent notation. */
   540 {
   652 static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path)
   541     PHYSFS_uint64 i;
   653 {
   542     for (i = 0; i < max; i++)
   654     PHYSFS_uint32 hashval;
   543     {
   655     ZIPentry *prev = NULL;
   544         ZIPentry *entry = &entries[i];
   656     ZIPentry *retval;
   545         if (entry->name != NULL)
   657 
   546             allocator.Free(entry->name);
   658     if (*path == '\0')
       
   659         return &info->root;
       
   660 
       
   661     hashval = zip_hash_string(info, path);
       
   662     for (retval = info->hash[hashval]; retval; retval = retval->hashnext)
       
   663     {
       
   664         if (strcmp(retval->name, path) == 0)
       
   665         {
       
   666             if (prev != NULL)  /* move this to the front of the list */
       
   667             {
       
   668                 prev->hashnext = retval->hashnext;
       
   669                 retval->hashnext = info->hash[hashval];
       
   670                 info->hash[hashval] = retval;
       
   671             } /* if */
       
   672 
       
   673             return retval;
       
   674         } /* if */
       
   675 
       
   676         prev = retval;
   547     } /* for */
   677     } /* for */
   548 
   678 
   549     allocator.Free(entries);
   679     BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, NULL);
   550 } /* zip_free_entries */
       
   551 
       
   552 
       
   553 /*
       
   554  * This will find the ZIPentry associated with a path in platform-independent
       
   555  *  notation. Directories don't have ZIPentries associated with them, but
       
   556  *  (*isDir) will be set to non-zero if a dir was hit.
       
   557  */
       
   558 static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
       
   559                                 int *isDir)
       
   560 {
       
   561     ZIPentry *a = info->entries;
       
   562     PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
       
   563     PHYSFS_sint64 lo = 0;
       
   564     PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
       
   565     PHYSFS_sint64 middle;
       
   566     const char *thispath = NULL;
       
   567     int rc;
       
   568 
       
   569     while (lo <= hi)
       
   570     {
       
   571         middle = lo + ((hi - lo) / 2);
       
   572         thispath = a[middle].name;
       
   573         rc = strncmp(path, thispath, pathlen);
       
   574 
       
   575         if (rc > 0)
       
   576             lo = middle + 1;
       
   577 
       
   578         else if (rc < 0)
       
   579             hi = middle - 1;
       
   580 
       
   581         else /* substring match...might be dir or entry or nothing. */
       
   582         {
       
   583             if (isDir != NULL)
       
   584             {
       
   585                 *isDir = (thispath[pathlen] == '/');
       
   586                 if (*isDir)
       
   587                     return NULL;
       
   588             } /* if */
       
   589 
       
   590             if (thispath[pathlen] == '\0') /* found entry? */
       
   591                 return &a[middle];
       
   592             /* adjust search params, try again. */
       
   593             else if (thispath[pathlen] > '/')
       
   594                 hi = middle - 1;
       
   595             else
       
   596                 lo = middle + 1;
       
   597         } /* if */
       
   598     } /* while */
       
   599 
       
   600     if (isDir != NULL)
       
   601         *isDir = 0;
       
   602 
       
   603     BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
       
   604 } /* zip_find_entry */
   680 } /* zip_find_entry */
   605 
   681 
   606 
   682 
   607 /* Convert paths from old, buggy DOS zippers... */
   683 /* Convert paths from old, buggy DOS zippers... */
   608 static void zip_convert_dos_path(ZIPentry *entry, char *path)
   684 static void zip_convert_dos_path(ZIPentry *entry, char *path)
   690 static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
   766 static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
   691 {
   767 {
   692     ZIPentry *entry;
   768     ZIPentry *entry;
   693 
   769 
   694     zip_expand_symlink_path(path);
   770     zip_expand_symlink_path(path);
   695     entry = zip_find_entry(info, path, NULL);
   771     entry = zip_find_entry(info, path);
   696     if (entry != NULL)
   772     if (entry != NULL)
   697     {
   773     {
   698         if (!zip_resolve(io, info, entry))  /* recursive! */
   774         if (!zip_resolve(io, info, entry))  /* recursive! */
   699             entry = NULL;
   775             entry = NULL;
   700         else
   776         else
   722 
   798 
   723     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   799     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   724 
   800 
   725     path = (char *) __PHYSFS_smallAlloc(size + 1);
   801     path = (char *) __PHYSFS_smallAlloc(size + 1);
   726     BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   802     BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   727 
   803     
   728     if (entry->compression_method == COMPMETH_NONE)
   804     if (entry->compression_method == COMPMETH_NONE)
   729         rc = __PHYSFS_readAll(io, path, size);
   805         rc = __PHYSFS_readAll(io, path, size);
   730 
   806 
   731     else  /* symlink target path is compressed... */
   807     else  /* symlink target path is compressed... */
   732     {
   808     {
   785      *  aren't zero. That seems to work well.
   861      *  aren't zero. That seems to work well.
   786      * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
   862      * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
   787      *  possible that's a Zip64 thing.
   863      *  possible that's a Zip64 thing.
   788      */
   864      */
   789 
   865 
       
   866     /* !!! FIXME: apparently these are zero if general purpose bit 3 is set,
       
   867        !!! FIXME:  which is probably true for Jar files, fwiw, but we don't
       
   868        !!! FIXME:  care about these values anyhow. */
       
   869 
   790     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   870     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   791     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
   871     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
   792     BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
   872     BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
   793     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
   873     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
   794     BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
   874     BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
   816 
   896 
   817 
   897 
   818 static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
   898 static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
   819 {
   899 {
   820     int retval = 1;
   900     int retval = 1;
   821     ZipResolveType resolve_type = entry->resolved;
   901     const ZipResolveType resolve_type = entry->resolved;
       
   902 
       
   903     if (resolve_type == ZIP_DIRECTORY)
       
   904         return 1;   /* we're good. */
   822 
   905 
   823     /* Don't bother if we've failed to resolve this entry before. */
   906     /* Don't bother if we've failed to resolve this entry before. */
   824     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
   907     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
   825     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
   908     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
   826 
   909 
   856             entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
   939             entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
   857     } /* if */
   940     } /* if */
   858 
   941 
   859     return retval;
   942     return retval;
   860 } /* zip_resolve */
   943 } /* zip_resolve */
       
   944 
       
   945 
       
   946 static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry);
       
   947 
       
   948 /* Fill in missing parent directories. */
       
   949 static ZIPentry *zip_hash_ancestors(ZIPinfo *info, char *name)
       
   950 {
       
   951     ZIPentry *retval = &info->root;
       
   952     char *sep = strrchr(name, '/');
       
   953 
       
   954     if (sep)
       
   955     {
       
   956         const size_t namelen = (sep - name) + 1;
       
   957 
       
   958         *sep = '\0';  /* chop off last piece. */
       
   959         retval = zip_find_entry(info, name);
       
   960         *sep = '/';
       
   961 
       
   962         if (retval != NULL)
       
   963         {
       
   964             if (retval->resolved != ZIP_DIRECTORY)
       
   965                 BAIL_MACRO(PHYSFS_ERR_CORRUPT, NULL);
       
   966             return retval;  /* already hashed. */
       
   967         } /* if */
       
   968 
       
   969         /* okay, this is a new dir. Build and hash us. */
       
   970         retval = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) + namelen);
       
   971         BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   972         memset(retval, '\0', sizeof (*retval));
       
   973         retval->name = ((char *) retval) + sizeof (ZIPentry);
       
   974         memcpy(retval->name, name, namelen - 1);
       
   975         retval->name[namelen - 1] = '\0';
       
   976         retval->resolved = ZIP_DIRECTORY;
       
   977         if (!zip_hash_entry(info, retval))
       
   978         {
       
   979             allocator.Free(retval);
       
   980             return NULL;
       
   981         } /* if */
       
   982     } /* else */
       
   983 
       
   984     return retval;
       
   985 } /* zip_hash_ancestors */
       
   986 
       
   987 
       
   988 static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry)
       
   989 {
       
   990     PHYSFS_uint32 hashval;
       
   991     ZIPentry *parent;
       
   992 
       
   993     assert(!zip_find_entry(info, entry->name));  /* checked elsewhere */
       
   994 
       
   995     parent = zip_hash_ancestors(info, entry->name);
       
   996     if (!parent)
       
   997         return 0;
       
   998 
       
   999     hashval = zip_hash_string(info, entry->name);
       
  1000     entry->hashnext = info->hash[hashval];
       
  1001     info->hash[hashval] = entry;
       
  1002 
       
  1003     entry->sibling = parent->children;
       
  1004     parent->children = entry;
       
  1005     return 1;
       
  1006 } /* zip_hash_entry */
       
  1007 
       
  1008 
       
  1009 static int zip_entry_is_symlink(const ZIPentry *entry)
       
  1010 {
       
  1011     return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
       
  1012             (entry->resolved == ZIP_BROKEN_SYMLINK) ||
       
  1013             (entry->symlink));
       
  1014 } /* zip_entry_is_symlink */
   861 
  1015 
   862 
  1016 
   863 static int zip_version_does_symlinks(PHYSFS_uint32 version)
  1017 static int zip_version_does_symlinks(PHYSFS_uint32 version)
   864 {
  1018 {
   865     int retval = 0;
  1019     int retval = 0;
   890 
  1044 
   891     return retval;
  1045     return retval;
   892 } /* zip_version_does_symlinks */
  1046 } /* zip_version_does_symlinks */
   893 
  1047 
   894 
  1048 
   895 static int zip_entry_is_symlink(const ZIPentry *entry)
       
   896 {
       
   897     return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
       
   898             (entry->resolved == ZIP_BROKEN_SYMLINK) ||
       
   899             (entry->symlink));
       
   900 } /* zip_entry_is_symlink */
       
   901 
       
   902 
       
   903 static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
  1049 static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
   904 {
  1050 {
   905     PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
  1051     PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
   906     return ( (zip_version_does_symlinks(entry->version)) &&
  1052     return ( (zip_version_does_symlinks(entry->version)) &&
   907              (entry->uncompressed_size > 0) &&
  1053              (entry->uncompressed_size > 0) &&
   933 
  1079 
   934     return ((PHYSFS_sint64) mktime(&unixtime));
  1080     return ((PHYSFS_sint64) mktime(&unixtime));
   935 } /* zip_dos_time_to_physfs_time */
  1081 } /* zip_dos_time_to_physfs_time */
   936 
  1082 
   937 
  1083 
   938 static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
  1084 static ZIPentry *zip_load_entry(PHYSFS_Io *io, const int zip64,
   939                           PHYSFS_uint64 ofs_fixup)
  1085                                 const PHYSFS_uint64 ofs_fixup)
   940 {
  1086 {
       
  1087     ZIPentry entry;
       
  1088     ZIPentry *retval = NULL;
   941     PHYSFS_uint16 fnamelen, extralen, commentlen;
  1089     PHYSFS_uint16 fnamelen, extralen, commentlen;
   942     PHYSFS_uint32 external_attr;
  1090     PHYSFS_uint32 external_attr;
   943     PHYSFS_uint32 starting_disk;
  1091     PHYSFS_uint32 starting_disk;
   944     PHYSFS_uint64 offset;
  1092     PHYSFS_uint64 offset;
   945     PHYSFS_uint16 ui16;
  1093     PHYSFS_uint16 ui16;
   946     PHYSFS_uint32 ui32;
  1094     PHYSFS_uint32 ui32;
   947     PHYSFS_sint64 si64;
  1095     PHYSFS_sint64 si64;
   948 
  1096 
       
  1097     memset(&entry, '\0', sizeof (entry));
       
  1098 
   949     /* sanity check with central directory signature... */
  1099     /* sanity check with central directory signature... */
   950     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1100     if (!readui32(io, &ui32)) return NULL;
   951     BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1101     BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, NULL);
   952 
  1102 
   953     /* Get the pertinent parts of the record... */
  1103     /* Get the pertinent parts of the record... */
   954     BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0);
  1104     if (!readui16(io, &entry.version)) return NULL;
   955     BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0);
  1105     if (!readui16(io, &entry.version_needed)) return NULL;
   956     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* general bits */
  1106     if (!readui16(io, &entry.general_bits)) return NULL;  /* general bits */
   957     BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0);
  1107     if (!readui16(io, &entry.compression_method)) return NULL;
   958     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1108     if (!readui32(io, &entry.dos_mod_time)) return NULL;
   959     entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
  1109     entry.last_mod_time = zip_dos_time_to_physfs_time(entry.dos_mod_time);
   960     BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
  1110     if (!readui32(io, &entry.crc)) return NULL;
   961     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1111     if (!readui32(io, &ui32)) return NULL;
   962     entry->compressed_size = (PHYSFS_uint64) ui32;
  1112     entry.compressed_size = (PHYSFS_uint64) ui32;
   963     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1113     if (!readui32(io, &ui32)) return NULL;
   964     entry->uncompressed_size = (PHYSFS_uint64) ui32;
  1114     entry.uncompressed_size = (PHYSFS_uint64) ui32;
   965     BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
  1115     if (!readui16(io, &fnamelen)) return NULL;
   966     BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
  1116     if (!readui16(io, &extralen)) return NULL;
   967     BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
  1117     if (!readui16(io, &commentlen)) return NULL;
   968     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
  1118     if (!readui16(io, &ui16)) return NULL;
   969     starting_disk = (PHYSFS_uint32) ui16;
  1119     starting_disk = (PHYSFS_uint32) ui16;
   970     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* internal file attribs */
  1120     if (!readui16(io, &ui16)) return NULL;  /* internal file attribs */
   971     BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
  1121     if (!readui32(io, &external_attr)) return NULL;
   972     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1122     if (!readui32(io, &ui32)) return NULL;
   973     offset = (PHYSFS_uint64) ui32;
  1123     offset = (PHYSFS_uint64) ui32;
   974 
  1124 
   975     entry->symlink = NULL;  /* will be resolved later, if necessary. */
  1125     retval = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) + fnamelen + 1);
   976     entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
  1126     BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   977                             ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
  1127     memcpy(retval, &entry, sizeof (*retval));
   978 
  1128     retval->name = ((char *) retval) + sizeof (ZIPentry);
   979     entry->name = (char *) allocator.Malloc(fnamelen + 1);
  1129 
   980     BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
  1130     if (!__PHYSFS_readAll(io, retval->name, fnamelen))
   981     if (!__PHYSFS_readAll(io, entry->name, fnamelen))
       
   982         goto zip_load_entry_puked;
  1131         goto zip_load_entry_puked;
   983 
  1132 
   984     entry->name[fnamelen] = '\0';  /* null-terminate the filename. */
  1133     retval->name[fnamelen] = '\0';  /* null-terminate the filename. */
   985     zip_convert_dos_path(entry, entry->name);
  1134     zip_convert_dos_path(retval, retval->name);
       
  1135 
       
  1136     retval->symlink = NULL;  /* will be resolved later, if necessary. */
       
  1137 
       
  1138     if (retval->name[fnamelen - 1] == '/')
       
  1139     {
       
  1140         retval->name[fnamelen - 1] = '\0';
       
  1141         retval->resolved = ZIP_DIRECTORY;
       
  1142     } /* if */
       
  1143     else
       
  1144     {
       
  1145         retval->resolved = (zip_has_symlink_attr(&entry, external_attr)) ?
       
  1146                                 ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
       
  1147     } /* else */
   986 
  1148 
   987     si64 = io->tell(io);
  1149     si64 = io->tell(io);
   988     if (si64 == -1)
  1150     if (si64 == -1)
   989         goto zip_load_entry_puked;
  1151         goto zip_load_entry_puked;
   990 
  1152 
   993      *  extended information extra field...
  1155      *  extended information extra field...
   994      */
  1156      */
   995     if ( (zip64) &&
  1157     if ( (zip64) &&
   996          ((offset == 0xFFFFFFFF) ||
  1158          ((offset == 0xFFFFFFFF) ||
   997           (starting_disk == 0xFFFFFFFF) ||
  1159           (starting_disk == 0xFFFFFFFF) ||
   998           (entry->compressed_size == 0xFFFFFFFF) ||
  1160           (retval->compressed_size == 0xFFFFFFFF) ||
   999           (entry->uncompressed_size == 0xFFFFFFFF)) )
  1161           (retval->uncompressed_size == 0xFFFFFFFF)) )
  1000     {
  1162     {
  1001         int found = 0;
  1163         int found = 0;
  1002         PHYSFS_uint16 sig, len;
  1164         PHYSFS_uint16 sig, len;
  1003         while (extralen > 4)
  1165         while (extralen > 4)
  1004         {
  1166         {
  1020             break;
  1182             break;
  1021         } /* while */
  1183         } /* while */
  1022 
  1184 
  1023         GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1185         GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1024 
  1186 
  1025         if (entry->uncompressed_size == 0xFFFFFFFF)
  1187         if (retval->uncompressed_size == 0xFFFFFFFF)
  1026         {
  1188         {
  1027             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1189             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1028             if (!readui64(io, &entry->uncompressed_size))
  1190             if (!readui64(io, &retval->uncompressed_size))
  1029                 goto zip_load_entry_puked;
  1191                 goto zip_load_entry_puked;
  1030             len -= 8;
  1192             len -= 8;
  1031         } /* if */
  1193         } /* if */
  1032 
  1194 
  1033         if (entry->compressed_size == 0xFFFFFFFF)
  1195         if (retval->compressed_size == 0xFFFFFFFF)
  1034         {
  1196         {
  1035             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1197             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1036             if (!readui64(io, &entry->compressed_size))
  1198             if (!readui64(io, &retval->compressed_size))
  1037                 goto zip_load_entry_puked;
  1199                 goto zip_load_entry_puked;
  1038             len -= 8;
  1200             len -= 8;
  1039         } /* if */
  1201         } /* if */
  1040 
  1202 
  1041         if (offset == 0xFFFFFFFF)
  1203         if (offset == 0xFFFFFFFF)
  1057         GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1219         GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1058     } /* if */
  1220     } /* if */
  1059 
  1221 
  1060     GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1222     GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1061 
  1223 
  1062     entry->offset = offset + ofs_fixup;
  1224     retval->offset = offset + ofs_fixup;
  1063 
  1225 
  1064     /* seek to the start of the next entry in the central directory... */
  1226     /* seek to the start of the next entry in the central directory... */
  1065     if (!io->seek(io, si64 + extralen + commentlen))
  1227     if (!io->seek(io, si64 + extralen + commentlen))
  1066         goto zip_load_entry_puked;
  1228         goto zip_load_entry_puked;
  1067 
  1229 
  1068     return 1;  /* success. */
  1230     return retval;  /* success. */
  1069 
  1231 
  1070 zip_load_entry_puked:
  1232 zip_load_entry_puked:
  1071     allocator.Free(entry->name);
  1233     allocator.Free(retval);
  1072     return 0;  /* failure. */
  1234     return NULL;  /* failure. */
  1073 } /* zip_load_entry */
  1235 } /* zip_load_entry */
  1074 
  1236 
  1075 
  1237 
  1076 static int zip_entry_cmp(void *_a, size_t one, size_t two)
  1238 /* This leaves things allocated on error; the caller will clean up the mess. */
  1077 {
  1239 static int zip_load_entries(ZIPinfo *info,
  1078     if (one != two)
       
  1079     {
       
  1080         const ZIPentry *a = (const ZIPentry *) _a;
       
  1081         return strcmp(a[one].name, a[two].name);
       
  1082     } /* if */
       
  1083 
       
  1084     return 0;
       
  1085 } /* zip_entry_cmp */
       
  1086 
       
  1087 
       
  1088 static void zip_entry_swap(void *_a, size_t one, size_t two)
       
  1089 {
       
  1090     if (one != two)
       
  1091     {
       
  1092         ZIPentry tmp;
       
  1093         ZIPentry *first = &(((ZIPentry *) _a)[one]);
       
  1094         ZIPentry *second = &(((ZIPentry *) _a)[two]);
       
  1095         memcpy(&tmp, first, sizeof (ZIPentry));
       
  1096         memcpy(first, second, sizeof (ZIPentry));
       
  1097         memcpy(second, &tmp, sizeof (ZIPentry));
       
  1098     } /* if */
       
  1099 } /* zip_entry_swap */
       
  1100 
       
  1101 
       
  1102 static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
       
  1103                             const PHYSFS_uint64 data_ofs,
  1240                             const PHYSFS_uint64 data_ofs,
  1104                             const PHYSFS_uint64 central_ofs)
  1241                             const PHYSFS_uint64 central_ofs,
  1105 {
  1242                             const PHYSFS_uint64 entry_count)
  1106     const PHYSFS_uint64 max = info->entryCount;
  1243 {
       
  1244     PHYSFS_Io *io = info->io;
  1107     const int zip64 = info->zip64;
  1245     const int zip64 = info->zip64;
  1108     PHYSFS_uint64 i;
  1246     PHYSFS_uint64 i;
  1109 
  1247 
  1110     BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
  1248     if (!io->seek(io, central_ofs))
  1111 
  1249         return 0;
  1112     info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
  1250 
  1113     BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0);
  1251     for (i = 0; i < entry_count; i++)
  1114 
  1252     {
  1115     for (i = 0; i < max; i++)
  1253         ZIPentry *entry = zip_load_entry(io, zip64, data_ofs);
  1116     {
  1254         ZIPentry *find;
  1117         if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
  1255 
  1118         {
  1256         if (!entry)
  1119             zip_free_entries(info->entries, i);
  1257             return 0;
       
  1258 
       
  1259         find = zip_find_entry(info, entry->name);
       
  1260         if (find != NULL)  /* duplicate? */
       
  1261         {
       
  1262             if (find->last_mod_time != 0)  /* duplicate? */
       
  1263             {
       
  1264                 allocator.Free(entry);
       
  1265                 BAIL_MACRO(PHYSFS_ERR_CORRUPT, 0);
       
  1266             } /* if */
       
  1267             else  /* we filled this in as a placeholder. Update it. */
       
  1268             {
       
  1269                 find->offset = entry->offset;
       
  1270                 find->version = entry->version;
       
  1271                 find->version_needed = entry->version_needed;
       
  1272                 find->compression_method = entry->compression_method;
       
  1273                 find->crc = entry->crc;
       
  1274                 find->compressed_size = entry->compressed_size;
       
  1275                 find->uncompressed_size = entry->uncompressed_size;
       
  1276                 find->last_mod_time = entry->last_mod_time;
       
  1277                 allocator.Free(entry);
       
  1278                 continue;
       
  1279             } /* else */
       
  1280         } /* if */
       
  1281 
       
  1282         if (!zip_hash_entry(info, entry))
       
  1283         {
       
  1284             allocator.Free(entry);
  1120             return 0;
  1285             return 0;
  1121         } /* if */
  1286         } /* if */
       
  1287 
       
  1288         if (zip_entry_is_tradional_crypto(entry))
       
  1289             info->has_crypto = 1;
  1122     } /* for */
  1290     } /* for */
  1123 
  1291 
  1124     __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
       
  1125     return 1;
  1292     return 1;
  1126 } /* zip_load_entries */
  1293 } /* zip_load_entries */
  1127 
  1294 
  1128 
  1295 
  1129 static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
  1296 static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
  1179 
  1346 
  1180     /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
  1347     /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
  1181     /*  Just try moving back at most 256k. Oh well. */
  1348     /*  Just try moving back at most 256k. Oh well. */
  1182     if ((offset < pos) && (pos > 4))
  1349     if ((offset < pos) && (pos > 4))
  1183     {
  1350     {
  1184         /* we assume you can eat this stack if you handle Zip64 files. */
  1351         const PHYSFS_uint64 maxbuflen = 256 * 1024;
  1185         PHYSFS_uint8 buf[256 * 1024];
       
  1186         PHYSFS_uint64 len = pos - offset;
  1352         PHYSFS_uint64 len = pos - offset;
       
  1353         PHYSFS_uint8 *buf = NULL;
  1187         PHYSFS_sint32 i;
  1354         PHYSFS_sint32 i;
  1188 
  1355 
  1189         if (len > sizeof (buf))
  1356         if (len > maxbuflen)
  1190             len = sizeof (buf);
  1357             len = maxbuflen;
  1191 
  1358 
  1192         BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
  1359         buf = (PHYSFS_uint8 *) __PHYSFS_smallAlloc(len);
  1193         BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
  1360         BAIL_IF_MACRO(!buf, PHYSFS_ERR_OUT_OF_MEMORY, -1);
       
  1361 
       
  1362         if (!io->seek(io, pos - len) || !__PHYSFS_readAll(io, buf, len))
       
  1363         {
       
  1364             __PHYSFS_smallFree(buf);
       
  1365             return -1;  /* error was set elsewhere. */
       
  1366         } /* if */
       
  1367 
  1194         for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
  1368         for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
  1195         {
  1369         {
  1196             if (buf[i] != 0x50)
  1370             if ( (buf[i] == 0x50) && (buf[i+1] == 0x4b) &&
  1197                 continue;
  1371                  (buf[i+2] == 0x06) && (buf[i+3] == 0x06) )
  1198             if ( (buf[i+1] == 0x4b) &&
  1372             {
  1199                  (buf[i+2] == 0x06) &&
  1373                 __PHYSFS_smallFree(buf);
  1200                  (buf[i+3] == 0x06) )
       
  1201                 return pos - (len - i);
  1374                 return pos - (len - i);
       
  1375             } /* if */
  1202         } /* for */
  1376         } /* for */
       
  1377 
       
  1378         __PHYSFS_smallFree(buf);
  1203     } /* if */
  1379     } /* if */
  1204 
  1380 
  1205     BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1);  /* didn't find it. */
  1381     BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1);  /* didn't find it. */
  1206 } /* zip64_find_end_of_central_dir */
  1382 } /* zip64_find_end_of_central_dir */
  1207 
  1383 
  1208 
  1384 
  1209 static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
  1385 static int zip64_parse_end_of_central_dir(ZIPinfo *info,
  1210                                           PHYSFS_uint64 *data_start,
  1386                                           PHYSFS_uint64 *data_start,
  1211                                           PHYSFS_uint64 *dir_ofs,
  1387                                           PHYSFS_uint64 *dir_ofs,
       
  1388                                           PHYSFS_uint64 *entry_count,
  1212                                           PHYSFS_sint64 pos)
  1389                                           PHYSFS_sint64 pos)
  1213 {
  1390 {
       
  1391     PHYSFS_Io *io = info->io;
  1214     PHYSFS_uint64 ui64;
  1392     PHYSFS_uint64 ui64;
  1215     PHYSFS_uint32 ui32;
  1393     PHYSFS_uint32 ui32;
  1216     PHYSFS_uint16 ui16;
  1394     PHYSFS_uint16 ui16;
  1217 
  1395 
  1218     /* We should be positioned right past the locator signature. */
  1396     /* We should be positioned right past the locator signature. */
  1276 
  1454 
  1277     /* total number of entries in the central dir on this disk */
  1455     /* total number of entries in the central dir on this disk */
  1278     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1456     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1279 
  1457 
  1280     /* total number of entries in the central dir */
  1458     /* total number of entries in the central dir */
  1281     BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
  1459     BAIL_IF_MACRO(!readui64(io, entry_count), ERRPASS, 0);
  1282     BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
  1460     BAIL_IF_MACRO(ui64 != *entry_count, PHYSFS_ERR_CORRUPT, 0);
  1283 
  1461 
  1284     /* size of the central directory */
  1462     /* size of the central directory */
  1285     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1463     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1286 
  1464 
  1287     /* offset of central directory */
  1465     /* offset of central directory */
  1297 
  1475 
  1298     return 1;  /* made it. */
  1476     return 1;  /* made it. */
  1299 } /* zip64_parse_end_of_central_dir */
  1477 } /* zip64_parse_end_of_central_dir */
  1300 
  1478 
  1301 
  1479 
  1302 static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
  1480 static int zip_parse_end_of_central_dir(ZIPinfo *info,
  1303                                         PHYSFS_uint64 *data_start,
  1481                                         PHYSFS_uint64 *data_start,
  1304                                         PHYSFS_uint64 *dir_ofs)
  1482                                         PHYSFS_uint64 *dir_ofs,
  1305 {
  1483                                         PHYSFS_uint64 *entry_count)
       
  1484 {
       
  1485     PHYSFS_Io *io = info->io;
  1306     PHYSFS_uint16 entryCount16;
  1486     PHYSFS_uint16 entryCount16;
  1307     PHYSFS_uint32 offset32;
  1487     PHYSFS_uint32 offset32;
  1308     PHYSFS_uint32 ui32;
  1488     PHYSFS_uint32 ui32;
  1309     PHYSFS_uint16 ui16;
  1489     PHYSFS_uint16 ui16;
  1310     PHYSFS_sint64 len;
  1490     PHYSFS_sint64 len;
  1320     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1500     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1321     BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1501     BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1322 
  1502 
  1323     /* Seek back to see if "Zip64 end of central directory locator" exists. */
  1503     /* Seek back to see if "Zip64 end of central directory locator" exists. */
  1324     /* this record is 20 bytes before end-of-central-dir */
  1504     /* this record is 20 bytes before end-of-central-dir */
  1325     rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
  1505     rc = zip64_parse_end_of_central_dir(info, data_start, dir_ofs,
  1326     BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
  1506                                         entry_count, pos - 20);
  1327     if (rc == 1)
  1507 
  1328         return 1;  /* we're done here. */
  1508     /* Error or success? Bounce out of here. Keep going if not zip64. */
       
  1509     if ((rc == 0) || (rc == 1))
       
  1510         return rc;
  1329 
  1511 
  1330     assert(rc == -1);  /* no error, just not a Zip64 archive. */
  1512     assert(rc == -1);  /* no error, just not a Zip64 archive. */
  1331 
  1513 
  1332     /* Not Zip64? Seek back to where we were and keep processing. */
  1514     /* Not Zip64? Seek back to where we were and keep processing. */
  1333     BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
  1515     BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
  1345 
  1527 
  1346     /* total number of entries in the central dir */
  1528     /* total number of entries in the central dir */
  1347     BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
  1529     BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
  1348     BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
  1530     BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
  1349 
  1531 
  1350     info->entryCount = entryCount16;
  1532     *entry_count = entryCount16;
  1351 
  1533 
  1352     /* size of the central directory */
  1534     /* size of the central directory */
  1353     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1535     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1354 
  1536 
  1355     /* offset of central directory */
  1537     /* offset of central directory */
  1382 
  1564 
  1383     return 1;  /* made it. */
  1565     return 1;  /* made it. */
  1384 } /* zip_parse_end_of_central_dir */
  1566 } /* zip_parse_end_of_central_dir */
  1385 
  1567 
  1386 
  1568 
       
  1569 static int zip_alloc_hashtable(ZIPinfo *info, const PHYSFS_uint64 entry_count)
       
  1570 {
       
  1571     size_t alloclen;
       
  1572 
       
  1573     info->hashBuckets = (size_t) (entry_count / 5);
       
  1574     if (!info->hashBuckets)
       
  1575         info->hashBuckets = 1;
       
  1576 
       
  1577     alloclen = info->hashBuckets * sizeof (ZIPentry *);
       
  1578     info->hash = (ZIPentry **) allocator.Malloc(alloclen);
       
  1579     BAIL_IF_MACRO(!info->hash, PHYSFS_ERR_OUT_OF_MEMORY, 0);
       
  1580     memset(info->hash, '\0', alloclen);
       
  1581 
       
  1582     return 1;
       
  1583 } /* zip_alloc_hashtable */
       
  1584 
       
  1585 static void ZIP_closeArchive(void *opaque);
       
  1586 
  1387 static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
  1587 static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
  1388 {
  1588 {
  1389     ZIPinfo *info = NULL;
  1589     ZIPinfo *info = NULL;
  1390     PHYSFS_uint64 data_start;
  1590     PHYSFS_uint64 dstart;  /* data start */
  1391     PHYSFS_uint64 cent_dir_ofs;
  1591     PHYSFS_uint64 cdir_ofs;  /* central dir offset */
       
  1592     PHYSFS_uint64 entry_count;
  1392 
  1593 
  1393     assert(io != NULL);  /* shouldn't ever happen. */
  1594     assert(io != NULL);  /* shouldn't ever happen. */
  1394 
  1595 
  1395     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  1596     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  1396     BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
  1597     BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
  1397 
  1598 
  1398     info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
  1599     info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
  1399     BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  1600     BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  1400     memset(info, '\0', sizeof (ZIPinfo));
  1601     memset(info, '\0', sizeof (ZIPinfo));
       
  1602     info->root.resolved = ZIP_DIRECTORY;
  1401     info->io = io;
  1603     info->io = io;
  1402 
  1604 
  1403     if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_dir_ofs))
  1605     if (!zip_parse_end_of_central_dir(info, &dstart, &cdir_ofs, &entry_count))
  1404         goto ZIP_openarchive_failed;
  1606         goto ZIP_openarchive_failed;
  1405 
  1607     else if (!zip_alloc_hashtable(info, entry_count))
  1406     if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
       
  1407         goto ZIP_openarchive_failed;
  1608         goto ZIP_openarchive_failed;
  1408 
  1609     else if (!zip_load_entries(info, dstart, cdir_ofs, entry_count))
       
  1610         goto ZIP_openarchive_failed;
       
  1611 
       
  1612     assert(info->root.sibling == NULL);
  1409     return info;
  1613     return info;
  1410 
  1614 
  1411 ZIP_openarchive_failed:
  1615 ZIP_openarchive_failed:
  1412     if (info != NULL)
  1616     info->io = NULL;  /* don't let ZIP_closeArchive destroy (io). */
  1413         allocator.Free(info);
  1617     ZIP_closeArchive(info);
  1414 
       
  1415     return NULL;
  1618     return NULL;
  1416 } /* ZIP_openArchive */
  1619 } /* ZIP_openArchive */
  1417 
  1620 
  1418 
  1621 
  1419 static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
  1622 static void ZIP_enumerateFiles(void *opaque, const char *dname,
  1420                                             int stop_on_first_find)
  1623                                PHYSFS_EnumFilesCallback cb,
  1421 {
       
  1422     PHYSFS_sint64 lo = 0;
       
  1423     PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
       
  1424     PHYSFS_sint64 middle;
       
  1425     PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
       
  1426     PHYSFS_sint64 retval = -1;
       
  1427     const char *name;
       
  1428     int rc;
       
  1429 
       
  1430     if (*path == '\0')  /* root dir? */
       
  1431         return 0;
       
  1432 
       
  1433     if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
       
  1434         dlen--;
       
  1435 
       
  1436     while (lo <= hi)
       
  1437     {
       
  1438         middle = lo + ((hi - lo) / 2);
       
  1439         name = info->entries[middle].name;
       
  1440         rc = strncmp(path, name, dlen);
       
  1441         if (rc == 0)
       
  1442         {
       
  1443             char ch = name[dlen];
       
  1444             if ('/' < ch) /* make sure this isn't just a substr match. */
       
  1445                 rc = -1;
       
  1446             else if ('/' > ch)
       
  1447                 rc = 1;
       
  1448             else
       
  1449             {
       
  1450                 if (stop_on_first_find) /* Just checking dir's existance? */
       
  1451                     return middle;
       
  1452 
       
  1453                 if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
       
  1454                     return (middle + 1);
       
  1455 
       
  1456                 /* there might be more entries earlier in the list. */
       
  1457                 retval = middle;
       
  1458                 hi = middle - 1;
       
  1459             } /* else */
       
  1460         } /* if */
       
  1461 
       
  1462         if (rc > 0)
       
  1463             lo = middle + 1;
       
  1464         else
       
  1465             hi = middle - 1;
       
  1466     } /* while */
       
  1467 
       
  1468     return retval;
       
  1469 } /* zip_find_start_of_dir */
       
  1470 
       
  1471 
       
  1472 /*
       
  1473  * Moved to seperate function so we can use alloca then immediately throw
       
  1474  *  away the allocated stack space...
       
  1475  */
       
  1476 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
       
  1477                            const char *odir, const char *str, PHYSFS_sint32 ln)
       
  1478 {
       
  1479     char *newstr = __PHYSFS_smallAlloc(ln + 1);
       
  1480     if (newstr == NULL)
       
  1481         return;
       
  1482 
       
  1483     memcpy(newstr, str, ln);
       
  1484     newstr[ln] = '\0';
       
  1485     cb(callbackdata, odir, newstr);
       
  1486     __PHYSFS_smallFree(newstr);
       
  1487 } /* doEnumCallback */
       
  1488 
       
  1489 
       
  1490 static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
       
  1491                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
       
  1492                                const char *origdir, void *callbackdata)
  1624                                const char *origdir, void *callbackdata)
  1493 {
  1625 {
  1494     ZIPinfo *info = ((ZIPinfo *) opaque);
  1626     ZIPinfo *info = ((ZIPinfo *) opaque);
  1495     PHYSFS_sint32 dlen, dlen_inc;
  1627     const ZIPentry *entry = zip_find_entry(info, dname);
  1496     PHYSFS_sint64 i, max;
  1628     if (entry && (entry->resolved == ZIP_DIRECTORY))
  1497 
  1629     {
  1498     i = zip_find_start_of_dir(info, dname, 0);
  1630         for (entry = entry->children; entry; entry = entry->sibling)
  1499     if (i == -1)  /* no such directory. */
  1631         {
  1500         return;
  1632             const char *ptr = strrchr(entry->name, '/');
  1501 
  1633             cb(callbackdata, origdir, ptr ? ptr + 1 : entry->name);
  1502     dlen = (PHYSFS_sint32) strlen(dname);
  1634         } /* for */
  1503     if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
  1635     } /* if */
  1504         dlen--;
       
  1505 
       
  1506     dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
       
  1507     max = (PHYSFS_sint64) info->entryCount;
       
  1508     while (i < max)
       
  1509     {
       
  1510         char *e = info->entries[i].name;
       
  1511         if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
       
  1512             break;  /* past end of this dir; we're done. */
       
  1513 
       
  1514         if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
       
  1515             i++;
       
  1516         else
       
  1517         {
       
  1518             char *add = e + dlen_inc;
       
  1519             char *ptr = strchr(add, '/');
       
  1520             PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
       
  1521             doEnumCallback(cb, callbackdata, origdir, add, ln);
       
  1522             ln += dlen_inc;  /* point past entry to children... */
       
  1523 
       
  1524             /* increment counter and skip children of subdirs... */
       
  1525             while ((++i < max) && (ptr != NULL))
       
  1526             {
       
  1527                 char *e_new = info->entries[i].name;
       
  1528                 if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
       
  1529                     break;
       
  1530             } /* while */
       
  1531         } /* else */
       
  1532     } /* while */
       
  1533 } /* ZIP_enumerateFiles */
  1636 } /* ZIP_enumerateFiles */
  1534 
  1637 
  1535 
  1638 
  1536 static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
  1639 static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
  1537 {
  1640 {
  1558 
  1661 
  1559     return retval;
  1662     return retval;
  1560 } /* zip_get_io */
  1663 } /* zip_get_io */
  1561 
  1664 
  1562 
  1665 
  1563 static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm,
  1666 static PHYSFS_Io *ZIP_openRead(void *opaque, const char *filename)
  1564                                int *fileExists)
       
  1565 {
  1667 {
  1566     PHYSFS_Io *retval = NULL;
  1668     PHYSFS_Io *retval = NULL;
  1567     ZIPinfo *info = (ZIPinfo *) opaque;
  1669     ZIPinfo *info = (ZIPinfo *) opaque;
  1568     ZIPentry *entry = zip_find_entry(info, fnm, NULL);
  1670     ZIPentry *entry = zip_find_entry(info, filename);
  1569     ZIPfileinfo *finfo = NULL;
  1671     ZIPfileinfo *finfo = NULL;
  1570 
  1672     PHYSFS_Io *io = NULL;
  1571     *fileExists = (entry != NULL);
  1673     PHYSFS_uint8 *password = NULL;
       
  1674     int i;
       
  1675 
       
  1676     /* if not found, see if maybe "$PASSWORD" is appended. */
       
  1677     if ((!entry) && (info->has_crypto))
       
  1678     {
       
  1679         const char *ptr = strrchr(filename, '$');
       
  1680         if (ptr != NULL)
       
  1681         {
       
  1682             const PHYSFS_uint64 len = (PHYSFS_uint64) (ptr - filename);
       
  1683             char *str = (char *) __PHYSFS_smallAlloc(len + 1);
       
  1684             BAIL_IF_MACRO(!str, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
  1685             memcpy(str, filename, len);
       
  1686             str[len] = '\0';
       
  1687             entry = zip_find_entry(info, str);
       
  1688             __PHYSFS_smallFree(str);
       
  1689             password = (PHYSFS_uint8 *) (ptr + 1);
       
  1690         } /* if */
       
  1691     } /* if */
       
  1692 
  1572     BAIL_IF_MACRO(!entry, ERRPASS, NULL);
  1693     BAIL_IF_MACRO(!entry, ERRPASS, NULL);
  1573 
  1694 
  1574     retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  1695     retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  1575     GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1696     GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1576 
  1697 
  1577     finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  1698     finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  1578     GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1699     GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1579     memset(finfo, '\0', sizeof (ZIPfileinfo));
  1700     memset(finfo, '\0', sizeof (ZIPfileinfo));
  1580 
  1701 
  1581     finfo->io = zip_get_io(info->io, info, entry);
  1702     io = zip_get_io(info->io, info, entry);
  1582     GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed);
  1703     GOTO_IF_MACRO(!io, ERRPASS, ZIP_openRead_failed);
       
  1704     finfo->io = io;
  1583     finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
  1705     finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
  1584     initializeZStream(&finfo->stream);
  1706     initializeZStream(&finfo->stream);
  1585 
  1707 
  1586     if (finfo->entry->compression_method != COMPMETH_NONE)
  1708     if (finfo->entry->compression_method != COMPMETH_NONE)
  1587     {
  1709     {
  1590             GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1712             GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1591         else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  1713         else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  1592             goto ZIP_openRead_failed;
  1714             goto ZIP_openRead_failed;
  1593     } /* if */
  1715     } /* if */
  1594 
  1716 
       
  1717     if (!zip_entry_is_tradional_crypto(entry))
       
  1718         GOTO_IF_MACRO(password != NULL, PHYSFS_ERR_BAD_PASSWORD, ZIP_openRead_failed);
       
  1719     else
       
  1720     {
       
  1721         PHYSFS_uint8 crypto_header[12];
       
  1722         GOTO_IF_MACRO(password == NULL, PHYSFS_ERR_BAD_PASSWORD, ZIP_openRead_failed);
       
  1723         if (io->read(io, crypto_header, 12) != 12)
       
  1724             goto ZIP_openRead_failed;
       
  1725         else if (!zip_prep_crypto_keys(finfo, crypto_header, password))
       
  1726             goto ZIP_openRead_failed;
       
  1727     } /* if */
       
  1728 
  1595     memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
  1729     memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
  1596     retval->opaque = finfo;
  1730     retval->opaque = finfo;
  1597 
  1731 
  1598     return retval;
  1732     return retval;
  1599 
  1733 
  1617 
  1751 
  1618     return NULL;
  1752     return NULL;
  1619 } /* ZIP_openRead */
  1753 } /* ZIP_openRead */
  1620 
  1754 
  1621 
  1755 
  1622 static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename)
  1756 static PHYSFS_Io *ZIP_openWrite(void *opaque, const char *filename)
  1623 {
  1757 {
  1624     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1758     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1625 } /* ZIP_openWrite */
  1759 } /* ZIP_openWrite */
  1626 
  1760 
  1627 
  1761 
  1628 static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename)
  1762 static PHYSFS_Io *ZIP_openAppend(void *opaque, const char *filename)
  1629 {
  1763 {
  1630     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1764     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1631 } /* ZIP_openAppend */
  1765 } /* ZIP_openAppend */
  1632 
  1766 
  1633 
  1767 
  1634 static void ZIP_closeArchive(PHYSFS_Dir *opaque)
  1768 static void ZIP_closeArchive(void *opaque)
  1635 {
  1769 {
  1636     ZIPinfo *zi = (ZIPinfo *) (opaque);
  1770     ZIPinfo *info = (ZIPinfo *) (opaque);
  1637     zi->io->destroy(zi->io);
  1771 
  1638     zip_free_entries(zi->entries, zi->entryCount);
  1772     if (!info)
  1639     allocator.Free(zi);
  1773         return;
       
  1774 
       
  1775     if (info->io)
       
  1776         info->io->destroy(info->io);
       
  1777 
       
  1778     assert(info->root.sibling == NULL);
       
  1779     assert(info->hash || (info->root.children == NULL));
       
  1780 
       
  1781     if (info->hash)
       
  1782     {
       
  1783         size_t i;
       
  1784         for (i = 0; i < info->hashBuckets; i++)
       
  1785         {
       
  1786             ZIPentry *entry;
       
  1787             ZIPentry *next;
       
  1788             for (entry = info->hash[i]; entry; entry = next)
       
  1789             {
       
  1790                 next = entry->hashnext;
       
  1791                 allocator.Free(entry);
       
  1792             } /* for */
       
  1793         } /* for */
       
  1794         allocator.Free(info->hash);
       
  1795     } /* if */
       
  1796 
       
  1797     allocator.Free(info);
  1640 } /* ZIP_closeArchive */
  1798 } /* ZIP_closeArchive */
  1641 
  1799 
  1642 
  1800 
  1643 static int ZIP_remove(PHYSFS_Dir *opaque, const char *name)
  1801 static int ZIP_remove(void *opaque, const char *name)
  1644 {
  1802 {
  1645     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1803     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1646 } /* ZIP_remove */
  1804 } /* ZIP_remove */
  1647 
  1805 
  1648 
  1806 
  1649 static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name)
  1807 static int ZIP_mkdir(void *opaque, const char *name)
  1650 {
  1808 {
  1651     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1809     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1652 } /* ZIP_mkdir */
  1810 } /* ZIP_mkdir */
  1653 
  1811 
  1654 
  1812 
  1655 static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists,
  1813 static int ZIP_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
  1656                     PHYSFS_Stat *stat)
  1814 {
  1657 {
  1815     ZIPinfo *info = (ZIPinfo *) opaque;
  1658     int isDir = 0;
  1816     const ZIPentry *entry = zip_find_entry(info, filename);
  1659     const ZIPinfo *info = (const ZIPinfo *) opaque;
       
  1660     const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
       
  1661 
  1817 
  1662     /* !!! FIXME: does this need to resolve entries here? */
  1818     /* !!! FIXME: does this need to resolve entries here? */
  1663 
  1819 
  1664     *exists = isDir || (entry != 0);
  1820     if (entry == NULL)
  1665     if (!*exists)
       
  1666         return 0;
  1821         return 0;
  1667 
  1822 
  1668     if (isDir)
  1823     else if (entry->resolved == ZIP_DIRECTORY)
  1669     {
  1824     {
  1670         stat->filesize = 0;
  1825         stat->filesize = 0;
  1671         stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  1826         stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  1672     } /* if */
  1827     } /* if */
  1673 
  1828 
  1692 } /* ZIP_stat */
  1847 } /* ZIP_stat */
  1693 
  1848 
  1694 
  1849 
  1695 const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
  1850 const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
  1696 {
  1851 {
       
  1852     CURRENT_PHYSFS_ARCHIVER_API_VERSION,
  1697     {
  1853     {
  1698         "ZIP",
  1854         "ZIP",
  1699         "PkZip/WinZip/Info-Zip compatible",
  1855         "PkZip/WinZip/Info-Zip compatible",
  1700         "Ryan C. Gordon <icculus@icculus.org>",
  1856         "Ryan C. Gordon <icculus@icculus.org>",
  1701         "http://icculus.org/physfs/",
  1857         "https://icculus.org/physfs/",
       
  1858         1,  /* supportsSymlinks */
  1702     },
  1859     },
  1703     ZIP_openArchive,        /* openArchive() method    */
  1860     ZIP_openArchive,
  1704     ZIP_enumerateFiles,     /* enumerateFiles() method */
  1861     ZIP_enumerateFiles,
  1705     ZIP_openRead,           /* openRead() method       */
  1862     ZIP_openRead,
  1706     ZIP_openWrite,          /* openWrite() method      */
  1863     ZIP_openWrite,
  1707     ZIP_openAppend,         /* openAppend() method     */
  1864     ZIP_openAppend,
  1708     ZIP_remove,             /* remove() method         */
  1865     ZIP_remove,
  1709     ZIP_mkdir,              /* mkdir() method          */
  1866     ZIP_mkdir,
  1710     ZIP_closeArchive,       /* closeArchive() method   */
  1867     ZIP_stat,
  1711     ZIP_stat                /* stat() method           */
  1868     ZIP_closeArchive
  1712 };
  1869 };
  1713 
  1870 
  1714 #endif  /* defined PHYSFS_SUPPORTS_ZIP */
  1871 #endif  /* defined PHYSFS_SUPPORTS_ZIP */
  1715 
  1872 
  1716 /* end of zip.c ... */
  1873 /* end of archiver_zip.c ... */
  1717 
  1874