misc/libphysfs/archiver_zip.c
changeset 12213 bb5522e88ab2
parent 12212 ea891871f481
child 12451 30da743f118b
equal deleted inserted replaced
12212:ea891871f481 12213:bb5522e88ab2
    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             inflateCopy(&finfo->stream, &str);
   424             inflateCopy(&finfo->stream, &str);
   316             inflateEnd(&str);
   425             inflateEnd(&str);
   317             finfo->uncompressed_position = finfo->compressed_position = 0;
   426             finfo->uncompressed_position = finfo->compressed_position = 0;
       
   427 
       
   428             if (encrypted)
       
   429                 memcpy(finfo->crypto_keys, finfo->initial_crypto_keys, 12);
   318         } /* if */
   430         } /* if */
   319 
   431 
   320         while (finfo->uncompressed_position != offset)
   432         while (finfo->uncompressed_position != offset)
   321         {
   433         {
   322             PHYSFS_uint8 buf[512];
   434             PHYSFS_uint8 buf[512];
   433     PHYSFS_sint32 maxread;
   545     PHYSFS_sint32 maxread;
   434     PHYSFS_sint32 totalread = 0;
   546     PHYSFS_sint32 totalread = 0;
   435     int found = 0;
   547     int found = 0;
   436 
   548 
   437     filelen = io->length(io);
   549     filelen = io->length(io);
   438     BAIL_IF_MACRO(filelen == -1, ERRPASS, 0);
   550     BAIL_IF_MACRO(filelen == -1, ERRPASS, -1);
   439 
   551 
   440     /*
   552     /*
   441      * Jump to the end of the file and start reading backwards.
   553      * Jump to the end of the file and start reading backwards.
   442      *  The last thing in the file is the zipfile comment, which is variable
   554      *  The last thing in the file is the zipfile comment, which is variable
   443      *  length, and the field that specifies its size is before it in the
   555      *  length, and the field that specifies its size is before it in the
   487                 (buf[i + 1] == 0x4B) &&
   599                 (buf[i + 1] == 0x4B) &&
   488                 (buf[i + 2] == 0x05) &&
   600                 (buf[i + 2] == 0x05) &&
   489                 (buf[i + 3] == 0x06) )
   601                 (buf[i + 3] == 0x06) )
   490             {
   602             {
   491                 found = 1;  /* that's the signature! */
   603                 found = 1;  /* that's the signature! */
   492                 break;
   604                 break;  
   493             } /* if */
   605             } /* if */
   494         } /* for */
   606         } /* for */
   495 
   607 
   496         if (found)
   608         if (found)
   497             break;
   609             break;
   535 
   647 
   536     return retval;
   648     return retval;
   537 } /* isZip */
   649 } /* isZip */
   538 
   650 
   539 
   651 
   540 static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
   652 /* Find the ZIPentry for a path in platform-independent notation. */
   541 {
   653 static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path)
   542     PHYSFS_uint64 i;
   654 {
   543     for (i = 0; i < max; i++)
   655     PHYSFS_uint32 hashval;
   544     {
   656     ZIPentry *prev = NULL;
   545         ZIPentry *entry = &entries[i];
   657     ZIPentry *retval;
   546         if (entry->name != NULL)
   658 
   547             allocator.Free(entry->name);
   659     if (*path == '\0')
       
   660         return &info->root;
       
   661 
       
   662     hashval = zip_hash_string(info, path);
       
   663     for (retval = info->hash[hashval]; retval; retval = retval->hashnext)
       
   664     {
       
   665         if (strcmp(retval->name, path) == 0)
       
   666         {
       
   667             if (prev != NULL)  /* move this to the front of the list */
       
   668             {
       
   669                 prev->hashnext = retval->hashnext;
       
   670                 retval->hashnext = info->hash[hashval];
       
   671                 info->hash[hashval] = retval;
       
   672             } /* if */
       
   673 
       
   674             return retval;
       
   675         } /* if */
       
   676 
       
   677         prev = retval;
   548     } /* for */
   678     } /* for */
   549 
   679 
   550     allocator.Free(entries);
   680     BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, NULL);
   551 } /* zip_free_entries */
       
   552 
       
   553 
       
   554 /*
       
   555  * This will find the ZIPentry associated with a path in platform-independent
       
   556  *  notation. Directories don't have ZIPentries associated with them, but
       
   557  *  (*isDir) will be set to non-zero if a dir was hit.
       
   558  */
       
   559 static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
       
   560                                 int *isDir)
       
   561 {
       
   562     ZIPentry *a = info->entries;
       
   563     PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
       
   564     PHYSFS_sint64 lo = 0;
       
   565     PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
       
   566     PHYSFS_sint64 middle;
       
   567     const char *thispath = NULL;
       
   568     int rc;
       
   569 
       
   570     while (lo <= hi)
       
   571     {
       
   572         middle = lo + ((hi - lo) / 2);
       
   573         thispath = a[middle].name;
       
   574         rc = strncmp(path, thispath, pathlen);
       
   575 
       
   576         if (rc > 0)
       
   577             lo = middle + 1;
       
   578 
       
   579         else if (rc < 0)
       
   580             hi = middle - 1;
       
   581 
       
   582         else /* substring match...might be dir or entry or nothing. */
       
   583         {
       
   584             if (isDir != NULL)
       
   585             {
       
   586                 *isDir = (thispath[pathlen] == '/');
       
   587                 if (*isDir)
       
   588                     return NULL;
       
   589             } /* if */
       
   590 
       
   591             if (thispath[pathlen] == '\0') /* found entry? */
       
   592                 return &a[middle];
       
   593             /* adjust search params, try again. */
       
   594             else if (thispath[pathlen] > '/')
       
   595                 hi = middle - 1;
       
   596             else
       
   597                 lo = middle + 1;
       
   598         } /* if */
       
   599     } /* while */
       
   600 
       
   601     if (isDir != NULL)
       
   602         *isDir = 0;
       
   603 
       
   604     BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
       
   605 } /* zip_find_entry */
   681 } /* zip_find_entry */
   606 
   682 
   607 
   683 
   608 /* Convert paths from old, buggy DOS zippers... */
   684 /* Convert paths from old, buggy DOS zippers... */
   609 static void zip_convert_dos_path(ZIPentry *entry, char *path)
   685 static void zip_convert_dos_path(ZIPentry *entry, char *path)
   691 static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
   767 static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
   692 {
   768 {
   693     ZIPentry *entry;
   769     ZIPentry *entry;
   694 
   770 
   695     zip_expand_symlink_path(path);
   771     zip_expand_symlink_path(path);
   696     entry = zip_find_entry(info, path, NULL);
   772     entry = zip_find_entry(info, path);
   697     if (entry != NULL)
   773     if (entry != NULL)
   698     {
   774     {
   699         if (!zip_resolve(io, info, entry))  /* recursive! */
   775         if (!zip_resolve(io, info, entry))  /* recursive! */
   700             entry = NULL;
   776             entry = NULL;
   701         else
   777         else
   723 
   799 
   724     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   800     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   725 
   801 
   726     path = (char *) __PHYSFS_smallAlloc(size + 1);
   802     path = (char *) __PHYSFS_smallAlloc(size + 1);
   727     BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   803     BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   728 
   804     
   729     if (entry->compression_method == COMPMETH_NONE)
   805     if (entry->compression_method == COMPMETH_NONE)
   730         rc = __PHYSFS_readAll(io, path, size);
   806         rc = __PHYSFS_readAll(io, path, size);
   731 
   807 
   732     else  /* symlink target path is compressed... */
   808     else  /* symlink target path is compressed... */
   733     {
   809     {
   786      *  aren't zero. That seems to work well.
   862      *  aren't zero. That seems to work well.
   787      * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
   863      * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
   788      *  possible that's a Zip64 thing.
   864      *  possible that's a Zip64 thing.
   789      */
   865      */
   790 
   866 
       
   867     /* !!! FIXME: apparently these are zero if general purpose bit 3 is set,
       
   868        !!! FIXME:  which is probably true for Jar files, fwiw, but we don't
       
   869        !!! FIXME:  care about these values anyhow. */
       
   870 
   791     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   871     BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
   792     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
   872     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
   793     BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
   873     BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
   794     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
   874     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
   795     BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
   875     BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
   817 
   897 
   818 
   898 
   819 static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
   899 static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
   820 {
   900 {
   821     int retval = 1;
   901     int retval = 1;
   822     ZipResolveType resolve_type = entry->resolved;
   902     const ZipResolveType resolve_type = entry->resolved;
       
   903 
       
   904     if (resolve_type == ZIP_DIRECTORY)
       
   905         return 1;   /* we're good. */
   823 
   906 
   824     /* Don't bother if we've failed to resolve this entry before. */
   907     /* Don't bother if we've failed to resolve this entry before. */
   825     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
   908     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
   826     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
   909     BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
   827 
   910 
   857             entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
   940             entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
   858     } /* if */
   941     } /* if */
   859 
   942 
   860     return retval;
   943     return retval;
   861 } /* zip_resolve */
   944 } /* zip_resolve */
       
   945 
       
   946 
       
   947 static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry);
       
   948 
       
   949 /* Fill in missing parent directories. */
       
   950 static ZIPentry *zip_hash_ancestors(ZIPinfo *info, char *name)
       
   951 {
       
   952     ZIPentry *retval = &info->root;
       
   953     char *sep = strrchr(name, '/');
       
   954 
       
   955     if (sep)
       
   956     {
       
   957         const size_t namelen = (sep - name) + 1;
       
   958 
       
   959         *sep = '\0';  /* chop off last piece. */
       
   960         retval = zip_find_entry(info, name);
       
   961         *sep = '/';
       
   962 
       
   963         if (retval != NULL)
       
   964         {
       
   965             if (retval->resolved != ZIP_DIRECTORY)
       
   966                 BAIL_MACRO(PHYSFS_ERR_CORRUPT, NULL);
       
   967             return retval;  /* already hashed. */
       
   968         } /* if */
       
   969 
       
   970         /* okay, this is a new dir. Build and hash us. */
       
   971         retval = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) + namelen);
       
   972         BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   973         memset(retval, '\0', sizeof (*retval));
       
   974         retval->name = ((char *) retval) + sizeof (ZIPentry);
       
   975         memcpy(retval->name, name, namelen);
       
   976         retval->name[namelen] = '\0';
       
   977         retval->resolved = ZIP_DIRECTORY;
       
   978         if (!zip_hash_entry(info, retval))
       
   979         {
       
   980             allocator.Free(retval);
       
   981             return NULL;
       
   982         } /* if */
       
   983     } /* else */
       
   984 
       
   985     return retval;
       
   986 } /* zip_hash_ancestors */
       
   987 
       
   988 
       
   989 static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry)
       
   990 {
       
   991     PHYSFS_uint32 hashval;
       
   992     ZIPentry *parent;
       
   993 
       
   994     assert(!zip_find_entry(info, entry->name));  /* checked elsewhere */
       
   995 
       
   996     parent = zip_hash_ancestors(info, entry->name);
       
   997     if (!parent)
       
   998         return 0;
       
   999 
       
  1000     hashval = zip_hash_string(info, entry->name);
       
  1001     entry->hashnext = info->hash[hashval];
       
  1002     info->hash[hashval] = entry;
       
  1003 
       
  1004     entry->sibling = parent->children;
       
  1005     parent->children = entry;
       
  1006     return 1;
       
  1007 } /* zip_hash_entry */
       
  1008 
       
  1009 
       
  1010 static int zip_entry_is_symlink(const ZIPentry *entry)
       
  1011 {
       
  1012     return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
       
  1013             (entry->resolved == ZIP_BROKEN_SYMLINK) ||
       
  1014             (entry->symlink));
       
  1015 } /* zip_entry_is_symlink */
   862 
  1016 
   863 
  1017 
   864 static int zip_version_does_symlinks(PHYSFS_uint32 version)
  1018 static int zip_version_does_symlinks(PHYSFS_uint32 version)
   865 {
  1019 {
   866     int retval = 0;
  1020     int retval = 0;
   891 
  1045 
   892     return retval;
  1046     return retval;
   893 } /* zip_version_does_symlinks */
  1047 } /* zip_version_does_symlinks */
   894 
  1048 
   895 
  1049 
   896 static int zip_entry_is_symlink(const ZIPentry *entry)
       
   897 {
       
   898     return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
       
   899             (entry->resolved == ZIP_BROKEN_SYMLINK) ||
       
   900             (entry->symlink));
       
   901 } /* zip_entry_is_symlink */
       
   902 
       
   903 
       
   904 static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
  1050 static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
   905 {
  1051 {
   906     PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
  1052     PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
   907     return ( (zip_version_does_symlinks(entry->version)) &&
  1053     return ( (zip_version_does_symlinks(entry->version)) &&
   908              (entry->uncompressed_size > 0) &&
  1054              (entry->uncompressed_size > 0) &&
   934 
  1080 
   935     return ((PHYSFS_sint64) mktime(&unixtime));
  1081     return ((PHYSFS_sint64) mktime(&unixtime));
   936 } /* zip_dos_time_to_physfs_time */
  1082 } /* zip_dos_time_to_physfs_time */
   937 
  1083 
   938 
  1084 
   939 static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
  1085 static ZIPentry *zip_load_entry(PHYSFS_Io *io, const int zip64,
   940                           PHYSFS_uint64 ofs_fixup)
  1086                                 const PHYSFS_uint64 ofs_fixup)
   941 {
  1087 {
       
  1088     ZIPentry entry;
       
  1089     ZIPentry *retval = NULL;
   942     PHYSFS_uint16 fnamelen, extralen, commentlen;
  1090     PHYSFS_uint16 fnamelen, extralen, commentlen;
   943     PHYSFS_uint32 external_attr;
  1091     PHYSFS_uint32 external_attr;
   944     PHYSFS_uint32 starting_disk;
  1092     PHYSFS_uint32 starting_disk;
   945     PHYSFS_uint64 offset;
  1093     PHYSFS_uint64 offset;
   946     PHYSFS_uint16 ui16;
  1094     PHYSFS_uint16 ui16;
   947     PHYSFS_uint32 ui32;
  1095     PHYSFS_uint32 ui32;
   948     PHYSFS_sint64 si64;
  1096     PHYSFS_sint64 si64;
   949 
  1097 
       
  1098     memset(&entry, '\0', sizeof (entry));
       
  1099 
   950     /* sanity check with central directory signature... */
  1100     /* sanity check with central directory signature... */
   951     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1101     if (!readui32(io, &ui32)) return NULL;
   952     BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1102     BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, NULL);
   953 
  1103 
   954     /* Get the pertinent parts of the record... */
  1104     /* Get the pertinent parts of the record... */
   955     BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0);
  1105     if (!readui16(io, &entry.version)) return NULL;
   956     BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0);
  1106     if (!readui16(io, &entry.version_needed)) return NULL;
   957     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* general bits */
  1107     if (!readui16(io, &entry.general_bits)) return NULL;  /* general bits */
   958     BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0);
  1108     if (!readui16(io, &entry.compression_method)) return NULL;
   959     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1109     if (!readui32(io, &entry.dos_mod_time)) return NULL;
   960     entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
  1110     entry.last_mod_time = zip_dos_time_to_physfs_time(entry.dos_mod_time);
   961     BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
  1111     if (!readui32(io, &entry.crc)) return NULL;
   962     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1112     if (!readui32(io, &ui32)) return NULL;
   963     entry->compressed_size = (PHYSFS_uint64) ui32;
  1113     entry.compressed_size = (PHYSFS_uint64) ui32;
   964     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1114     if (!readui32(io, &ui32)) return NULL;
   965     entry->uncompressed_size = (PHYSFS_uint64) ui32;
  1115     entry.uncompressed_size = (PHYSFS_uint64) ui32;
   966     BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
  1116     if (!readui16(io, &fnamelen)) return NULL;
   967     BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
  1117     if (!readui16(io, &extralen)) return NULL;
   968     BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
  1118     if (!readui16(io, &commentlen)) return NULL;
   969     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
  1119     if (!readui16(io, &ui16)) return NULL;
   970     starting_disk = (PHYSFS_uint32) ui16;
  1120     starting_disk = (PHYSFS_uint32) ui16;
   971     BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* internal file attribs */
  1121     if (!readui16(io, &ui16)) return NULL;  /* internal file attribs */
   972     BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
  1122     if (!readui32(io, &external_attr)) return NULL;
   973     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1123     if (!readui32(io, &ui32)) return NULL;
   974     offset = (PHYSFS_uint64) ui32;
  1124     offset = (PHYSFS_uint64) ui32;
   975 
  1125 
   976     entry->symlink = NULL;  /* will be resolved later, if necessary. */
  1126     retval = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) + fnamelen + 1);
   977     entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
  1127     BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
   978                             ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
  1128     memcpy(retval, &entry, sizeof (*retval));
   979 
  1129     retval->name = ((char *) retval) + sizeof (ZIPentry);
   980     entry->name = (char *) allocator.Malloc(fnamelen + 1);
  1130 
   981     BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
  1131     if (!__PHYSFS_readAll(io, retval->name, fnamelen))
   982     if (!__PHYSFS_readAll(io, entry->name, fnamelen))
       
   983         goto zip_load_entry_puked;
  1132         goto zip_load_entry_puked;
   984 
  1133 
   985     entry->name[fnamelen] = '\0';  /* null-terminate the filename. */
  1134     retval->name[fnamelen] = '\0';  /* null-terminate the filename. */
   986     zip_convert_dos_path(entry, entry->name);
  1135     zip_convert_dos_path(retval, retval->name);
       
  1136 
       
  1137     retval->symlink = NULL;  /* will be resolved later, if necessary. */
       
  1138 
       
  1139     if (retval->name[fnamelen - 1] == '/')
       
  1140     {
       
  1141         retval->name[fnamelen - 1] = '\0';
       
  1142         retval->resolved = ZIP_DIRECTORY;
       
  1143     } /* if */
       
  1144     else
       
  1145     {
       
  1146         retval->resolved = (zip_has_symlink_attr(&entry, external_attr)) ?
       
  1147                                 ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
       
  1148     } /* else */
   987 
  1149 
   988     si64 = io->tell(io);
  1150     si64 = io->tell(io);
   989     if (si64 == -1)
  1151     if (si64 == -1)
   990         goto zip_load_entry_puked;
  1152         goto zip_load_entry_puked;
   991 
  1153 
   994      *  extended information extra field...
  1156      *  extended information extra field...
   995      */
  1157      */
   996     if ( (zip64) &&
  1158     if ( (zip64) &&
   997          ((offset == 0xFFFFFFFF) ||
  1159          ((offset == 0xFFFFFFFF) ||
   998           (starting_disk == 0xFFFFFFFF) ||
  1160           (starting_disk == 0xFFFFFFFF) ||
   999           (entry->compressed_size == 0xFFFFFFFF) ||
  1161           (retval->compressed_size == 0xFFFFFFFF) ||
  1000           (entry->uncompressed_size == 0xFFFFFFFF)) )
  1162           (retval->uncompressed_size == 0xFFFFFFFF)) )
  1001     {
  1163     {
  1002         int found = 0;
  1164         int found = 0;
  1003         PHYSFS_uint16 sig, len;
  1165         PHYSFS_uint16 sig, len;
  1004         while (extralen > 4)
  1166         while (extralen > 4)
  1005         {
  1167         {
  1021             break;
  1183             break;
  1022         } /* while */
  1184         } /* while */
  1023 
  1185 
  1024         GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1186         GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1025 
  1187 
  1026         if (entry->uncompressed_size == 0xFFFFFFFF)
  1188         if (retval->uncompressed_size == 0xFFFFFFFF)
  1027         {
  1189         {
  1028             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1190             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1029             if (!readui64(io, &entry->uncompressed_size))
  1191             if (!readui64(io, &retval->uncompressed_size))
  1030                 goto zip_load_entry_puked;
  1192                 goto zip_load_entry_puked;
  1031             len -= 8;
  1193             len -= 8;
  1032         } /* if */
  1194         } /* if */
  1033 
  1195 
  1034         if (entry->compressed_size == 0xFFFFFFFF)
  1196         if (retval->compressed_size == 0xFFFFFFFF)
  1035         {
  1197         {
  1036             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1198             GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1037             if (!readui64(io, &entry->compressed_size))
  1199             if (!readui64(io, &retval->compressed_size))
  1038                 goto zip_load_entry_puked;
  1200                 goto zip_load_entry_puked;
  1039             len -= 8;
  1201             len -= 8;
  1040         } /* if */
  1202         } /* if */
  1041 
  1203 
  1042         if (offset == 0xFFFFFFFF)
  1204         if (offset == 0xFFFFFFFF)
  1058         GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1220         GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1059     } /* if */
  1221     } /* if */
  1060 
  1222 
  1061     GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1223     GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
  1062 
  1224 
  1063     entry->offset = offset + ofs_fixup;
  1225     retval->offset = offset + ofs_fixup;
  1064 
  1226 
  1065     /* seek to the start of the next entry in the central directory... */
  1227     /* seek to the start of the next entry in the central directory... */
  1066     if (!io->seek(io, si64 + extralen + commentlen))
  1228     if (!io->seek(io, si64 + extralen + commentlen))
  1067         goto zip_load_entry_puked;
  1229         goto zip_load_entry_puked;
  1068 
  1230 
  1069     return 1;  /* success. */
  1231     return retval;  /* success. */
  1070 
  1232 
  1071 zip_load_entry_puked:
  1233 zip_load_entry_puked:
  1072     allocator.Free(entry->name);
  1234     allocator.Free(retval);
  1073     return 0;  /* failure. */
  1235     return NULL;  /* failure. */
  1074 } /* zip_load_entry */
  1236 } /* zip_load_entry */
  1075 
  1237 
  1076 
  1238 
  1077 static int zip_entry_cmp(void *_a, size_t one, size_t two)
  1239 /* This leaves things allocated on error; the caller will clean up the mess. */
  1078 {
  1240 static int zip_load_entries(ZIPinfo *info,
  1079     if (one != two)
       
  1080     {
       
  1081         const ZIPentry *a = (const ZIPentry *) _a;
       
  1082         return strcmp(a[one].name, a[two].name);
       
  1083     } /* if */
       
  1084 
       
  1085     return 0;
       
  1086 } /* zip_entry_cmp */
       
  1087 
       
  1088 
       
  1089 static void zip_entry_swap(void *_a, size_t one, size_t two)
       
  1090 {
       
  1091     if (one != two)
       
  1092     {
       
  1093         ZIPentry tmp;
       
  1094         ZIPentry *first = &(((ZIPentry *) _a)[one]);
       
  1095         ZIPentry *second = &(((ZIPentry *) _a)[two]);
       
  1096         memcpy(&tmp, first, sizeof (ZIPentry));
       
  1097         memcpy(first, second, sizeof (ZIPentry));
       
  1098         memcpy(second, &tmp, sizeof (ZIPentry));
       
  1099     } /* if */
       
  1100 } /* zip_entry_swap */
       
  1101 
       
  1102 
       
  1103 static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
       
  1104                             const PHYSFS_uint64 data_ofs,
  1241                             const PHYSFS_uint64 data_ofs,
  1105                             const PHYSFS_uint64 central_ofs)
  1242                             const PHYSFS_uint64 central_ofs,
  1106 {
  1243                             const PHYSFS_uint64 entry_count)
  1107     const PHYSFS_uint64 max = info->entryCount;
  1244 {
       
  1245     PHYSFS_Io *io = info->io;
  1108     const int zip64 = info->zip64;
  1246     const int zip64 = info->zip64;
  1109     PHYSFS_uint64 i;
  1247     PHYSFS_uint64 i;
  1110 
  1248 
  1111     BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
  1249     if (!io->seek(io, central_ofs))
  1112 
  1250         return 0;
  1113     info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
  1251 
  1114     BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0);
  1252     for (i = 0; i < entry_count; i++)
  1115 
  1253     {
  1116     for (i = 0; i < max; i++)
  1254         ZIPentry *entry = zip_load_entry(io, zip64, data_ofs);
  1117     {
  1255         ZIPentry *find;
  1118         if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
  1256 
  1119         {
  1257         if (!entry)
  1120             zip_free_entries(info->entries, i);
  1258             return 0;
       
  1259 
       
  1260         find = zip_find_entry(info, entry->name);
       
  1261         if (find != NULL)  /* duplicate? */
       
  1262         {
       
  1263             if (find->last_mod_time != 0)  /* duplicate? */
       
  1264             {
       
  1265                 allocator.Free(entry);
       
  1266                 BAIL_MACRO(PHYSFS_ERR_CORRUPT, 0);
       
  1267             } /* if */
       
  1268             else  /* we filled this in as a placeholder. Update it. */
       
  1269             {
       
  1270                 find->offset = entry->offset;
       
  1271                 find->version = entry->version;
       
  1272                 find->version_needed = entry->version_needed;
       
  1273                 find->compression_method = entry->compression_method;
       
  1274                 find->crc = entry->crc;
       
  1275                 find->compressed_size = entry->compressed_size;
       
  1276                 find->uncompressed_size = entry->uncompressed_size;
       
  1277                 find->last_mod_time = entry->last_mod_time;
       
  1278                 allocator.Free(entry);
       
  1279                 continue;
       
  1280             } /* else */
       
  1281         } /* if */
       
  1282 
       
  1283         if (!zip_hash_entry(info, entry))
       
  1284         {
       
  1285             allocator.Free(entry);
  1121             return 0;
  1286             return 0;
  1122         } /* if */
  1287         } /* if */
       
  1288 
       
  1289         if (zip_entry_is_tradional_crypto(entry))
       
  1290             info->has_crypto = 1;
  1123     } /* for */
  1291     } /* for */
  1124 
  1292 
  1125     __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
       
  1126     return 1;
  1293     return 1;
  1127 } /* zip_load_entries */
  1294 } /* zip_load_entries */
  1128 
  1295 
  1129 
  1296 
  1130 static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
  1297 static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
  1180 
  1347 
  1181     /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
  1348     /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
  1182     /*  Just try moving back at most 256k. Oh well. */
  1349     /*  Just try moving back at most 256k. Oh well. */
  1183     if ((offset < pos) && (pos > 4))
  1350     if ((offset < pos) && (pos > 4))
  1184     {
  1351     {
  1185         /* we assume you can eat this stack if you handle Zip64 files. */
  1352         const PHYSFS_uint64 maxbuflen = 256 * 1024;
  1186         PHYSFS_uint8 buf[256 * 1024];
       
  1187         PHYSFS_uint64 len = pos - offset;
  1353         PHYSFS_uint64 len = pos - offset;
       
  1354         PHYSFS_uint8 *buf = NULL;
  1188         PHYSFS_sint32 i;
  1355         PHYSFS_sint32 i;
  1189 
  1356 
  1190         if (len > sizeof (buf))
  1357         if (len > maxbuflen)
  1191             len = sizeof (buf);
  1358             len = maxbuflen;
  1192 
  1359 
  1193         BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
  1360         buf = (PHYSFS_uint8 *) __PHYSFS_smallAlloc(len);
  1194         BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
  1361         BAIL_IF_MACRO(!buf, PHYSFS_ERR_OUT_OF_MEMORY, -1);
       
  1362 
       
  1363         if (!io->seek(io, pos - len) || !__PHYSFS_readAll(io, buf, len))
       
  1364         {
       
  1365             __PHYSFS_smallFree(buf);
       
  1366             return -1;  /* error was set elsewhere. */
       
  1367         } /* if */
       
  1368 
  1195         for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
  1369         for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
  1196         {
  1370         {
  1197             if (buf[i] != 0x50)
  1371             if ( (buf[i] == 0x50) && (buf[i+1] == 0x4b) &&
  1198                 continue;
  1372                  (buf[i+2] == 0x06) && (buf[i+3] == 0x06) )
  1199             if ( (buf[i+1] == 0x4b) &&
  1373             {
  1200                  (buf[i+2] == 0x06) &&
  1374                 __PHYSFS_smallFree(buf);
  1201                  (buf[i+3] == 0x06) )
       
  1202                 return pos - (len - i);
  1375                 return pos - (len - i);
       
  1376             } /* if */
  1203         } /* for */
  1377         } /* for */
       
  1378 
       
  1379         __PHYSFS_smallFree(buf);
  1204     } /* if */
  1380     } /* if */
  1205 
  1381 
  1206     BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1);  /* didn't find it. */
  1382     BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1);  /* didn't find it. */
  1207 } /* zip64_find_end_of_central_dir */
  1383 } /* zip64_find_end_of_central_dir */
  1208 
  1384 
  1209 
  1385 
  1210 static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
  1386 static int zip64_parse_end_of_central_dir(ZIPinfo *info,
  1211                                           PHYSFS_uint64 *data_start,
  1387                                           PHYSFS_uint64 *data_start,
  1212                                           PHYSFS_uint64 *dir_ofs,
  1388                                           PHYSFS_uint64 *dir_ofs,
       
  1389                                           PHYSFS_uint64 *entry_count,
  1213                                           PHYSFS_sint64 pos)
  1390                                           PHYSFS_sint64 pos)
  1214 {
  1391 {
       
  1392     PHYSFS_Io *io = info->io;
  1215     PHYSFS_uint64 ui64;
  1393     PHYSFS_uint64 ui64;
  1216     PHYSFS_uint32 ui32;
  1394     PHYSFS_uint32 ui32;
  1217     PHYSFS_uint16 ui16;
  1395     PHYSFS_uint16 ui16;
  1218 
  1396 
  1219     /* We should be positioned right past the locator signature. */
  1397     /* We should be positioned right past the locator signature. */
  1277 
  1455 
  1278     /* total number of entries in the central dir on this disk */
  1456     /* total number of entries in the central dir on this disk */
  1279     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1457     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1280 
  1458 
  1281     /* total number of entries in the central dir */
  1459     /* total number of entries in the central dir */
  1282     BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
  1460     BAIL_IF_MACRO(!readui64(io, entry_count), ERRPASS, 0);
  1283     BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
  1461     BAIL_IF_MACRO(ui64 != *entry_count, PHYSFS_ERR_CORRUPT, 0);
  1284 
  1462 
  1285     /* size of the central directory */
  1463     /* size of the central directory */
  1286     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1464     BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
  1287 
  1465 
  1288     /* offset of central directory */
  1466     /* offset of central directory */
  1298 
  1476 
  1299     return 1;  /* made it. */
  1477     return 1;  /* made it. */
  1300 } /* zip64_parse_end_of_central_dir */
  1478 } /* zip64_parse_end_of_central_dir */
  1301 
  1479 
  1302 
  1480 
  1303 static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
  1481 static int zip_parse_end_of_central_dir(ZIPinfo *info,
  1304                                         PHYSFS_uint64 *data_start,
  1482                                         PHYSFS_uint64 *data_start,
  1305                                         PHYSFS_uint64 *dir_ofs)
  1483                                         PHYSFS_uint64 *dir_ofs,
  1306 {
  1484                                         PHYSFS_uint64 *entry_count)
       
  1485 {
       
  1486     PHYSFS_Io *io = info->io;
  1307     PHYSFS_uint16 entryCount16;
  1487     PHYSFS_uint16 entryCount16;
  1308     PHYSFS_uint32 offset32;
  1488     PHYSFS_uint32 offset32;
  1309     PHYSFS_uint32 ui32;
  1489     PHYSFS_uint32 ui32;
  1310     PHYSFS_uint16 ui16;
  1490     PHYSFS_uint16 ui16;
  1311     PHYSFS_sint64 len;
  1491     PHYSFS_sint64 len;
  1321     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1501     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1322     BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1502     BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
  1323 
  1503 
  1324     /* Seek back to see if "Zip64 end of central directory locator" exists. */
  1504     /* Seek back to see if "Zip64 end of central directory locator" exists. */
  1325     /* this record is 20 bytes before end-of-central-dir */
  1505     /* this record is 20 bytes before end-of-central-dir */
  1326     rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
  1506     rc = zip64_parse_end_of_central_dir(info, data_start, dir_ofs,
  1327     BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
  1507                                         entry_count, pos - 20);
  1328     if (rc == 1)
  1508 
  1329         return 1;  /* we're done here. */
  1509     /* Error or success? Bounce out of here. Keep going if not zip64. */
       
  1510     if ((rc == 0) || (rc == 1))
       
  1511         return rc;
  1330 
  1512 
  1331     assert(rc == -1);  /* no error, just not a Zip64 archive. */
  1513     assert(rc == -1);  /* no error, just not a Zip64 archive. */
  1332 
  1514 
  1333     /* Not Zip64? Seek back to where we were and keep processing. */
  1515     /* Not Zip64? Seek back to where we were and keep processing. */
  1334     BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
  1516     BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
  1346 
  1528 
  1347     /* total number of entries in the central dir */
  1529     /* total number of entries in the central dir */
  1348     BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
  1530     BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
  1349     BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
  1531     BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
  1350 
  1532 
  1351     info->entryCount = entryCount16;
  1533     *entry_count = entryCount16;
  1352 
  1534 
  1353     /* size of the central directory */
  1535     /* size of the central directory */
  1354     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1536     BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
  1355 
  1537 
  1356     /* offset of central directory */
  1538     /* offset of central directory */
  1383 
  1565 
  1384     return 1;  /* made it. */
  1566     return 1;  /* made it. */
  1385 } /* zip_parse_end_of_central_dir */
  1567 } /* zip_parse_end_of_central_dir */
  1386 
  1568 
  1387 
  1569 
       
  1570 static int zip_alloc_hashtable(ZIPinfo *info, const PHYSFS_uint64 entry_count)
       
  1571 {
       
  1572     size_t alloclen;
       
  1573 
       
  1574     info->hashBuckets = (size_t) (entry_count / 5);
       
  1575     if (!info->hashBuckets)
       
  1576         info->hashBuckets = 1;
       
  1577 
       
  1578     alloclen = info->hashBuckets * sizeof (ZIPentry *);
       
  1579     info->hash = (ZIPentry **) allocator.Malloc(alloclen);
       
  1580     BAIL_IF_MACRO(!info->hash, PHYSFS_ERR_OUT_OF_MEMORY, 0);
       
  1581     memset(info->hash, '\0', alloclen);
       
  1582 
       
  1583     return 1;
       
  1584 } /* zip_alloc_hashtable */
       
  1585 
       
  1586 static void ZIP_closeArchive(void *opaque);
       
  1587 
  1388 static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
  1588 static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
  1389 {
  1589 {
  1390     ZIPinfo *info = NULL;
  1590     ZIPinfo *info = NULL;
  1391     PHYSFS_uint64 data_start;
  1591     PHYSFS_uint64 dstart;  /* data start */
  1392     PHYSFS_uint64 cent_dir_ofs;
  1592     PHYSFS_uint64 cdir_ofs;  /* central dir offset */
       
  1593     PHYSFS_uint64 entry_count;
  1393 
  1594 
  1394     assert(io != NULL);  /* shouldn't ever happen. */
  1595     assert(io != NULL);  /* shouldn't ever happen. */
  1395 
  1596 
  1396     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  1597     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  1397     BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
  1598     BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
  1398 
  1599 
  1399     info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
  1600     info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
  1400     BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  1601     BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  1401     memset(info, '\0', sizeof (ZIPinfo));
  1602     memset(info, '\0', sizeof (ZIPinfo));
       
  1603     info->root.resolved = ZIP_DIRECTORY;
  1402     info->io = io;
  1604     info->io = io;
  1403 
  1605 
  1404     if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_dir_ofs))
  1606     if (!zip_parse_end_of_central_dir(info, &dstart, &cdir_ofs, &entry_count))
  1405         goto ZIP_openarchive_failed;
  1607         goto ZIP_openarchive_failed;
  1406 
  1608     else if (!zip_alloc_hashtable(info, entry_count))
  1407     if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
       
  1408         goto ZIP_openarchive_failed;
  1609         goto ZIP_openarchive_failed;
  1409 
  1610     else if (!zip_load_entries(info, dstart, cdir_ofs, entry_count))
       
  1611         goto ZIP_openarchive_failed;
       
  1612 
       
  1613     assert(info->root.sibling == NULL);
  1410     return info;
  1614     return info;
  1411 
  1615 
  1412 ZIP_openarchive_failed:
  1616 ZIP_openarchive_failed:
  1413     if (info != NULL)
  1617     info->io = NULL;  /* don't let ZIP_closeArchive destroy (io). */
  1414         allocator.Free(info);
  1618     ZIP_closeArchive(info);
  1415 
       
  1416     return NULL;
  1619     return NULL;
  1417 } /* ZIP_openArchive */
  1620 } /* ZIP_openArchive */
  1418 
  1621 
  1419 
  1622 
  1420 static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
  1623 static void ZIP_enumerateFiles(void *opaque, const char *dname,
  1421                                             int stop_on_first_find)
  1624                                PHYSFS_EnumFilesCallback cb,
  1422 {
       
  1423     PHYSFS_sint64 lo = 0;
       
  1424     PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
       
  1425     PHYSFS_sint64 middle;
       
  1426     PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
       
  1427     PHYSFS_sint64 retval = -1;
       
  1428     const char *name;
       
  1429     int rc;
       
  1430 
       
  1431     if (*path == '\0')  /* root dir? */
       
  1432         return 0;
       
  1433 
       
  1434     if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
       
  1435         dlen--;
       
  1436 
       
  1437     while (lo <= hi)
       
  1438     {
       
  1439         middle = lo + ((hi - lo) / 2);
       
  1440         name = info->entries[middle].name;
       
  1441         rc = strncmp(path, name, dlen);
       
  1442         if (rc == 0)
       
  1443         {
       
  1444             char ch = name[dlen];
       
  1445             if ('/' < ch) /* make sure this isn't just a substr match. */
       
  1446                 rc = -1;
       
  1447             else if ('/' > ch)
       
  1448                 rc = 1;
       
  1449             else
       
  1450             {
       
  1451                 if (stop_on_first_find) /* Just checking dir's existance? */
       
  1452                     return middle;
       
  1453 
       
  1454                 if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
       
  1455                     return (middle + 1);
       
  1456 
       
  1457                 /* there might be more entries earlier in the list. */
       
  1458                 retval = middle;
       
  1459                 hi = middle - 1;
       
  1460             } /* else */
       
  1461         } /* if */
       
  1462 
       
  1463         if (rc > 0)
       
  1464             lo = middle + 1;
       
  1465         else
       
  1466             hi = middle - 1;
       
  1467     } /* while */
       
  1468 
       
  1469     return retval;
       
  1470 } /* zip_find_start_of_dir */
       
  1471 
       
  1472 
       
  1473 /*
       
  1474  * Moved to seperate function so we can use alloca then immediately throw
       
  1475  *  away the allocated stack space...
       
  1476  */
       
  1477 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
       
  1478                            const char *odir, const char *str, PHYSFS_sint32 ln)
       
  1479 {
       
  1480     char *newstr = __PHYSFS_smallAlloc(ln + 1);
       
  1481     if (newstr == NULL)
       
  1482         return;
       
  1483 
       
  1484     memcpy(newstr, str, ln);
       
  1485     newstr[ln] = '\0';
       
  1486     cb(callbackdata, odir, newstr);
       
  1487     __PHYSFS_smallFree(newstr);
       
  1488 } /* doEnumCallback */
       
  1489 
       
  1490 
       
  1491 static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
       
  1492                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
       
  1493                                const char *origdir, void *callbackdata)
  1625                                const char *origdir, void *callbackdata)
  1494 {
  1626 {
  1495     ZIPinfo *info = ((ZIPinfo *) opaque);
  1627     ZIPinfo *info = ((ZIPinfo *) opaque);
  1496     PHYSFS_sint32 dlen, dlen_inc;
  1628     const ZIPentry *entry = zip_find_entry(info, dname);
  1497     PHYSFS_sint64 i, max;
  1629     if (entry && (entry->resolved == ZIP_DIRECTORY))
  1498 
  1630     {
  1499     i = zip_find_start_of_dir(info, dname, 0);
  1631         for (entry = entry->children; entry; entry = entry->sibling)
  1500     if (i == -1)  /* no such directory. */
  1632         {
  1501         return;
  1633             const char *ptr = strrchr(entry->name, '/');
  1502 
  1634             cb(callbackdata, origdir, ptr ? ptr + 1 : entry->name);
  1503     dlen = (PHYSFS_sint32) strlen(dname);
  1635         } /* for */
  1504     if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
  1636     } /* if */
  1505         dlen--;
       
  1506 
       
  1507     dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
       
  1508     max = (PHYSFS_sint64) info->entryCount;
       
  1509     while (i < max)
       
  1510     {
       
  1511         char *e = info->entries[i].name;
       
  1512         if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
       
  1513             break;  /* past end of this dir; we're done. */
       
  1514 
       
  1515         if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
       
  1516             i++;
       
  1517         else
       
  1518         {
       
  1519             char *add = e + dlen_inc;
       
  1520             char *ptr = strchr(add, '/');
       
  1521             PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
       
  1522             doEnumCallback(cb, callbackdata, origdir, add, ln);
       
  1523             ln += dlen_inc;  /* point past entry to children... */
       
  1524 
       
  1525             /* increment counter and skip children of subdirs... */
       
  1526             while ((++i < max) && (ptr != NULL))
       
  1527             {
       
  1528                 char *e_new = info->entries[i].name;
       
  1529                 if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
       
  1530                     break;
       
  1531             } /* while */
       
  1532         } /* else */
       
  1533     } /* while */
       
  1534 } /* ZIP_enumerateFiles */
  1637 } /* ZIP_enumerateFiles */
  1535 
  1638 
  1536 
  1639 
  1537 static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
  1640 static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
  1538 {
  1641 {
  1559 
  1662 
  1560     return retval;
  1663     return retval;
  1561 } /* zip_get_io */
  1664 } /* zip_get_io */
  1562 
  1665 
  1563 
  1666 
  1564 static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm,
  1667 static PHYSFS_Io *ZIP_openRead(void *opaque, const char *filename)
  1565                                int *fileExists)
       
  1566 {
  1668 {
  1567     PHYSFS_Io *retval = NULL;
  1669     PHYSFS_Io *retval = NULL;
  1568     ZIPinfo *info = (ZIPinfo *) opaque;
  1670     ZIPinfo *info = (ZIPinfo *) opaque;
  1569     ZIPentry *entry = zip_find_entry(info, fnm, NULL);
  1671     ZIPentry *entry = zip_find_entry(info, filename);
  1570     ZIPfileinfo *finfo = NULL;
  1672     ZIPfileinfo *finfo = NULL;
  1571 
  1673     PHYSFS_Io *io = NULL;
  1572     *fileExists = (entry != NULL);
  1674     PHYSFS_uint8 *password = NULL;
       
  1675     int i;
       
  1676 
       
  1677     /* if not found, see if maybe "$PASSWORD" is appended. */
       
  1678     if ((!entry) && (info->has_crypto))
       
  1679     {
       
  1680         const char *ptr = strrchr(filename, '$');
       
  1681         if (ptr != NULL)
       
  1682         {
       
  1683             const PHYSFS_uint64 len = (PHYSFS_uint64) (ptr - filename);
       
  1684             char *str = (char *) __PHYSFS_smallAlloc(len + 1);
       
  1685             BAIL_IF_MACRO(!str, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
  1686             memcpy(str, filename, len);
       
  1687             str[len] = '\0';
       
  1688             entry = zip_find_entry(info, str);
       
  1689             __PHYSFS_smallFree(str);
       
  1690             password = (PHYSFS_uint8 *) (ptr + 1);
       
  1691         } /* if */
       
  1692     } /* if */
       
  1693 
  1573     BAIL_IF_MACRO(!entry, ERRPASS, NULL);
  1694     BAIL_IF_MACRO(!entry, ERRPASS, NULL);
  1574 
  1695 
  1575     retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  1696     retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  1576     GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1697     GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1577 
  1698 
  1578     finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  1699     finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  1579     GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1700     GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1580     memset(finfo, '\0', sizeof (ZIPfileinfo));
  1701     memset(finfo, '\0', sizeof (ZIPfileinfo));
  1581 
  1702 
  1582     finfo->io = zip_get_io(info->io, info, entry);
  1703     io = zip_get_io(info->io, info, entry);
  1583     GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed);
  1704     GOTO_IF_MACRO(!io, ERRPASS, ZIP_openRead_failed);
       
  1705     finfo->io = io;
  1584     finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
  1706     finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
  1585     initializeZStream(&finfo->stream);
  1707     initializeZStream(&finfo->stream);
  1586 
  1708 
  1587     if (finfo->entry->compression_method != COMPMETH_NONE)
  1709     if (finfo->entry->compression_method != COMPMETH_NONE)
  1588     {
  1710     {
  1591             GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1713             GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1592         else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  1714         else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  1593             goto ZIP_openRead_failed;
  1715             goto ZIP_openRead_failed;
  1594     } /* if */
  1716     } /* if */
  1595 
  1717 
       
  1718     if (!zip_entry_is_tradional_crypto(entry))
       
  1719         GOTO_IF_MACRO(password != NULL, PHYSFS_ERR_BAD_PASSWORD, ZIP_openRead_failed);
       
  1720     else
       
  1721     {
       
  1722         PHYSFS_uint8 crypto_header[12];
       
  1723         GOTO_IF_MACRO(password == NULL, PHYSFS_ERR_BAD_PASSWORD, ZIP_openRead_failed);
       
  1724         if (io->read(io, crypto_header, 12) != 12)
       
  1725             goto ZIP_openRead_failed;
       
  1726         else if (!zip_prep_crypto_keys(finfo, crypto_header, password))
       
  1727             goto ZIP_openRead_failed;
       
  1728     } /* if */
       
  1729 
  1596     memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
  1730     memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
  1597     retval->opaque = finfo;
  1731     retval->opaque = finfo;
  1598 
  1732 
  1599     return retval;
  1733     return retval;
  1600 
  1734 
  1618 
  1752 
  1619     return NULL;
  1753     return NULL;
  1620 } /* ZIP_openRead */
  1754 } /* ZIP_openRead */
  1621 
  1755 
  1622 
  1756 
  1623 static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename)
  1757 static PHYSFS_Io *ZIP_openWrite(void *opaque, const char *filename)
  1624 {
  1758 {
  1625     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1759     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1626 } /* ZIP_openWrite */
  1760 } /* ZIP_openWrite */
  1627 
  1761 
  1628 
  1762 
  1629 static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename)
  1763 static PHYSFS_Io *ZIP_openAppend(void *opaque, const char *filename)
  1630 {
  1764 {
  1631     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1765     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
  1632 } /* ZIP_openAppend */
  1766 } /* ZIP_openAppend */
  1633 
  1767 
  1634 
  1768 
  1635 static void ZIP_closeArchive(PHYSFS_Dir *opaque)
  1769 static void ZIP_closeArchive(void *opaque)
  1636 {
  1770 {
  1637     ZIPinfo *zi = (ZIPinfo *) (opaque);
  1771     ZIPinfo *info = (ZIPinfo *) (opaque);
  1638     zi->io->destroy(zi->io);
  1772 
  1639     zip_free_entries(zi->entries, zi->entryCount);
  1773     if (!info)
  1640     allocator.Free(zi);
  1774         return;
       
  1775 
       
  1776     if (info->io)
       
  1777         info->io->destroy(info->io);
       
  1778 
       
  1779     assert(info->root.sibling == NULL);
       
  1780     assert(info->hash || (info->root.children == NULL));
       
  1781 
       
  1782     if (info->hash)
       
  1783     {
       
  1784         size_t i;
       
  1785         for (i = 0; i < info->hashBuckets; i++)
       
  1786         {
       
  1787             ZIPentry *entry;
       
  1788             ZIPentry *next;
       
  1789             for (entry = info->hash[i]; entry; entry = next)
       
  1790             {
       
  1791                 next = entry->hashnext;
       
  1792                 allocator.Free(entry);
       
  1793             } /* for */
       
  1794         } /* for */
       
  1795         allocator.Free(info->hash);
       
  1796     } /* if */
       
  1797 
       
  1798     allocator.Free(info);
  1641 } /* ZIP_closeArchive */
  1799 } /* ZIP_closeArchive */
  1642 
  1800 
  1643 
  1801 
  1644 static int ZIP_remove(PHYSFS_Dir *opaque, const char *name)
  1802 static int ZIP_remove(void *opaque, const char *name)
  1645 {
  1803 {
  1646     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1804     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1647 } /* ZIP_remove */
  1805 } /* ZIP_remove */
  1648 
  1806 
  1649 
  1807 
  1650 static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name)
  1808 static int ZIP_mkdir(void *opaque, const char *name)
  1651 {
  1809 {
  1652     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1810     BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
  1653 } /* ZIP_mkdir */
  1811 } /* ZIP_mkdir */
  1654 
  1812 
  1655 
  1813 
  1656 static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists,
  1814 static int ZIP_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
  1657                     PHYSFS_Stat *stat)
  1815 {
  1658 {
  1816     ZIPinfo *info = (ZIPinfo *) opaque;
  1659     int isDir = 0;
  1817     const ZIPentry *entry = zip_find_entry(info, filename);
  1660     const ZIPinfo *info = (const ZIPinfo *) opaque;
       
  1661     const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
       
  1662 
  1818 
  1663     /* !!! FIXME: does this need to resolve entries here? */
  1819     /* !!! FIXME: does this need to resolve entries here? */
  1664 
  1820 
  1665     *exists = isDir || (entry != 0);
  1821     if (entry == NULL)
  1666     if (!*exists)
       
  1667         return 0;
  1822         return 0;
  1668 
  1823 
  1669     if (isDir)
  1824     else if (entry->resolved == ZIP_DIRECTORY)
  1670     {
  1825     {
  1671         stat->filesize = 0;
  1826         stat->filesize = 0;
  1672         stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  1827         stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  1673     } /* if */
  1828     } /* if */
  1674 
  1829 
  1693 } /* ZIP_stat */
  1848 } /* ZIP_stat */
  1694 
  1849 
  1695 
  1850 
  1696 const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
  1851 const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
  1697 {
  1852 {
       
  1853     CURRENT_PHYSFS_ARCHIVER_API_VERSION,
  1698     {
  1854     {
  1699         "ZIP",
  1855         "ZIP",
  1700         "PkZip/WinZip/Info-Zip compatible",
  1856         "PkZip/WinZip/Info-Zip compatible",
  1701         "Ryan C. Gordon <icculus@icculus.org>",
  1857         "Ryan C. Gordon <icculus@icculus.org>",
  1702         "http://icculus.org/physfs/",
  1858         "https://icculus.org/physfs/",
       
  1859         1,  /* supportsSymlinks */
  1703     },
  1860     },
  1704     ZIP_openArchive,        /* openArchive() method    */
  1861     ZIP_openArchive,
  1705     ZIP_enumerateFiles,     /* enumerateFiles() method */
  1862     ZIP_enumerateFiles,
  1706     ZIP_openRead,           /* openRead() method       */
  1863     ZIP_openRead,
  1707     ZIP_openWrite,          /* openWrite() method      */
  1864     ZIP_openWrite,
  1708     ZIP_openAppend,         /* openAppend() method     */
  1865     ZIP_openAppend,
  1709     ZIP_remove,             /* remove() method         */
  1866     ZIP_remove,
  1710     ZIP_mkdir,              /* mkdir() method          */
  1867     ZIP_mkdir,
  1711     ZIP_closeArchive,       /* closeArchive() method   */
  1868     ZIP_stat,
  1712     ZIP_stat                /* stat() method           */
  1869     ZIP_closeArchive
  1713 };
  1870 };
  1714 
  1871 
  1715 #endif  /* defined PHYSFS_SUPPORTS_ZIP */
  1872 #endif  /* defined PHYSFS_SUPPORTS_ZIP */
  1716 
  1873 
  1717 /* end of zip.c ... */
  1874 /* end of archiver_zip.c ... */
  1718 
  1875