--- a/src/archiver_zip.c Sat Apr 07 21:33:18 2012 -0400
+++ b/src/archiver_zip.c Fri Jun 01 05:44:50 2012 -0400
@@ -64,13 +64,13 @@
char *name; /* Name of file in archive */
struct _ZIPentry *symlink; /* NULL or file we symlink to */
ZipResolveType resolved; /* Have we resolved file/symlink? */
- PHYSFS_uint32 offset; /* offset of data in archive */
+ PHYSFS_uint64 offset; /* offset of data in archive */
PHYSFS_uint16 version; /* version made by */
PHYSFS_uint16 version_needed; /* version needed to extract */
PHYSFS_uint16 compression_method; /* compression method */
PHYSFS_uint32 crc; /* crc-32 */
- PHYSFS_uint32 compressed_size; /* compressed size */
- PHYSFS_uint32 uncompressed_size; /* uncompressed size */
+ PHYSFS_uint64 compressed_size; /* compressed size */
+ PHYSFS_uint64 uncompressed_size; /* uncompressed size */
PHYSFS_sint64 last_mod_time; /* last file mod time */
} ZIPentry;
@@ -80,8 +80,9 @@
typedef struct
{
PHYSFS_Io *io;
- PHYSFS_uint16 entryCount; /* Number of files in ZIP. */
- ZIPentry *entries; /* info on all files in ZIP. */
+ int zip64; /* non-zero if this is a Zip64 archive. */
+ PHYSFS_uint64 entryCount; /* Number of files in ZIP. */
+ ZIPentry *entries; /* info on all files in ZIP. */
} ZIPinfo;
/*
@@ -99,9 +100,12 @@
/* Magic numbers... */
-#define ZIP_LOCAL_FILE_SIG 0x04034b50
-#define ZIP_CENTRAL_DIR_SIG 0x02014b50
-#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
+#define ZIP_LOCAL_FILE_SIG 0x04034b50
+#define ZIP_CENTRAL_DIR_SIG 0x02014b50
+#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
+#define ZIP64_END_OF_CENTRAL_DIR_SIG 0x06064b50
+#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50
+#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG 0x0001
/* compression methods... */
#define COMPMETH_NONE 0
@@ -165,6 +169,17 @@
/*
+ * Read an unsigned 64-bit int and swap to native byte order.
+ */
+static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
+{
+ PHYSFS_uint64 v;
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+ *val = PHYSFS_swapULE64(v);
+ return 1;
+} /* readui64 */
+
+/*
* Read an unsigned 32-bit int and swap to native byte order.
*/
static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
@@ -322,7 +337,7 @@
static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
{
const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
- return finfo->entry->uncompressed_size;
+ return (PHYSFS_sint64) finfo->entry->uncompressed_size;
} /* ZIP_length */
@@ -521,9 +536,9 @@
} /* isZip */
-static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max)
+static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
{
- PHYSFS_uint32 i;
+ PHYSFS_uint64 i;
for (i = 0; i < max; i++)
{
ZIPentry *entry = &entries[i];
@@ -545,9 +560,9 @@
{
ZIPentry *a = info->entries;
PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
- PHYSFS_sint32 lo = 0;
- PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
- PHYSFS_sint32 middle;
+ PHYSFS_sint64 lo = 0;
+ PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
+ PHYSFS_sint64 middle;
const char *thispath = NULL;
int rc;
@@ -695,7 +710,7 @@
static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
{
- const PHYSFS_uint32 size = entry->uncompressed_size;
+ const PHYSFS_uint64 size = entry->uncompressed_size;
char *path = NULL;
int rc = 0;
@@ -716,7 +731,7 @@
else /* symlink target path is compressed... */
{
z_stream stream;
- const PHYSFS_uint32 complen = entry->compressed_size;
+ const PHYSFS_uint64 complen = entry->compressed_size;
PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
if (compressed != NULL)
{
@@ -768,6 +783,8 @@
* archive created with Sun's Java tools, apparently. We only
* consider this archive corrupted if those entries don't match and
* aren't zero. That seems to work well.
+ * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
+ * possible that's a Zip64 thing.
*/
BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
@@ -781,10 +798,15 @@
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); /* date/time */
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0);
+
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 && (ui32!=entry->compressed_size),PHYSFS_ERR_CORRUPT,0);
+ BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+ (ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0);
+
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32&&(ui32!=entry->uncompressed_size),PHYSFS_ERR_CORRUPT,0);
+ BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+ (ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0);
+
BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
@@ -913,10 +935,13 @@
} /* zip_dos_time_to_physfs_time */
-static int zip_load_entry(PHYSFS_Io *io, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
+static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
+ PHYSFS_uint64 ofs_fixup)
{
PHYSFS_uint16 fnamelen, extralen, commentlen;
PHYSFS_uint32 external_attr;
+ PHYSFS_uint32 starting_disk;
+ PHYSFS_uint64 offset;
PHYSFS_uint16 ui16;
PHYSFS_uint32 ui32;
PHYSFS_sint64 si64;
@@ -933,16 +958,19 @@
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &entry->compressed_size), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &entry->uncompressed_size), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ entry->compressed_size = (PHYSFS_uint64) ui32;
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ entry->uncompressed_size = (PHYSFS_uint64) ui32;
BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* disk number start */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ starting_disk = (PHYSFS_uint32) ui16;
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* internal file attribs */
BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &entry->offset), ERRPASS, 0);
- entry->offset += ofs_fixup;
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ offset = (PHYSFS_uint64) ui32;
entry->symlink = NULL; /* will be resolved later, if necessary. */
entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
@@ -960,7 +988,80 @@
if (si64 == -1)
goto zip_load_entry_puked;
- /* seek to the start of the next entry in the central directory... */
+ /*
+ * The actual sizes didn't fit in 32-bits; look for the Zip64
+ * extended information extra field...
+ */
+ if ( (zip64) &&
+ ((offset == 0xFFFFFFFF) ||
+ (starting_disk == 0xFFFFFFFF) ||
+ (entry->compressed_size == 0xFFFFFFFF) ||
+ (entry->uncompressed_size == 0xFFFFFFFF)) )
+ {
+ int found = 0;
+ PHYSFS_uint16 sig, len;
+ while (extralen > 4)
+ {
+ if (!readui16(io, &sig))
+ goto zip_load_entry_puked;
+ else if (!readui16(io, &len))
+ goto zip_load_entry_puked;
+
+ si64 += 4 + len;
+ extralen -= 4 + len;
+ if (sig != ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG)
+ {
+ if (!io->seek(io, si64))
+ goto zip_load_entry_puked;
+ continue;
+ } /* if */
+
+ found = 1;
+ break;
+ } /* while */
+
+ GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+ if (entry->uncompressed_size == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &entry->uncompressed_size))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (entry->compressed_size == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &entry->compressed_size))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (offset == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &offset))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (starting_disk == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui32(io, &starting_disk))
+ goto zip_load_entry_puked;
+ len -= 4;
+ } /* if */
+
+ GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ } /* if */
+
+ GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+ entry->offset = offset + ofs_fixup;
+
+ /* seek to the start of the next entry in the central directory... */
if (!io->seek(io, si64 + extralen + commentlen))
goto zip_load_entry_puked;
@@ -972,7 +1073,7 @@
} /* zip_load_entry */
-static int zip_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+static int zip_entry_cmp(void *_a, size_t one, size_t two)
{
if (one != two)
{
@@ -984,7 +1085,7 @@
} /* zip_entry_cmp */
-static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+static void zip_entry_swap(void *_a, size_t one, size_t two)
{
if (one != two)
{
@@ -999,10 +1100,12 @@
static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
- PHYSFS_uint32 data_ofs, PHYSFS_uint32 central_ofs)
+ const PHYSFS_uint64 data_ofs,
+ const PHYSFS_uint64 central_ofs)
{
- PHYSFS_uint32 max = info->entryCount;
- PHYSFS_uint32 i;
+ const PHYSFS_uint64 max = info->entryCount;
+ const int zip64 = info->zip64;
+ PHYSFS_uint64 i;
BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
@@ -1011,26 +1114,203 @@
for (i = 0; i < max; i++)
{
- if (!zip_load_entry(io, &info->entries[i], data_ofs))
+ if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
{
zip_free_entries(info->entries, i);
return 0;
} /* if */
} /* for */
- __PHYSFS_sort(info->entries, max, zip_entry_cmp, zip_entry_swap);
+ __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
return 1;
} /* zip_load_entries */
+static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
+ PHYSFS_sint64 _pos,
+ PHYSFS_uint64 offset)
+{
+ /*
+ * Naturally, the offset is useless to us; it is the offset from the
+ * start of file, which is meaningless if we've appended this .zip to
+ * a self-extracting .exe. We need to find this on our own. It should
+ * be directly before the locator record, but the record in question,
+ * like the original end-of-central-directory record, ends with a
+ * variable-length field. Unlike the original, which has to store the
+ * size of that variable-length field in a 16-bit int and thus has to be
+ * within 64k, the new one gets 64-bits.
+ *
+ * Fortunately, the only currently-specified record for that variable
+ * length block is some weird proprietary thing that deals with EBCDIC
+ * and tape backups or something. So we don't seek far.
+ */
+
+ PHYSFS_uint32 ui32;
+ const PHYSFS_uint64 pos = (PHYSFS_uint64) _pos;
+
+ assert(_pos > 0);
+
+ /* Try offset specified in the Zip64 end of central directory locator. */
+ /* This works if the entire PHYSFS_Io is the zip file. */
+ BAIL_IF_MACRO(!io->seek(io, offset), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return offset;
+
+ /* Try 56 bytes before the Zip64 end of central directory locator. */
+ /* This works if the record isn't variable length and is version 1. */
+ if (pos > 56)
+ {
+ BAIL_IF_MACRO(!io->seek(io, pos-56), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return pos-56;
+ } /* if */
+
+ /* Try 84 bytes before the Zip64 end of central directory locator. */
+ /* This works if the record isn't variable length and is version 2. */
+ if (pos > 84)
+ {
+ BAIL_IF_MACRO(!io->seek(io, pos-84), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return pos-84;
+ } /* if */
+
+ /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
+ /* Just try moving back at most 256k. Oh well. */
+ if ((offset < pos) && (pos > 4))
+ {
+ /* we assume you can eat this stack if you handle Zip64 files. */
+ PHYSFS_uint8 buf[256 * 1024];
+ PHYSFS_uint64 len = pos - offset;
+ PHYSFS_uint32 i;
+
+ if (len > sizeof (buf))
+ len = sizeof (buf);
+
+ BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
+ for (i = len - 4; i >= 0; i--)
+ {
+ if (buf[i] != 0x50)
+ continue;
+ if ( (buf[i+1] == 0x4b) &&
+ (buf[i+2] == 0x06) &&
+ (buf[i+3] == 0x06) )
+ return pos - (len - i);
+ } /* for */
+ } /* if */
+
+ BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1); /* didn't find it. */
+} /* zip64_find_end_of_central_dir */
+
+
+static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
+ PHYSFS_uint64 *data_start,
+ PHYSFS_uint64 *dir_ofs,
+ PHYSFS_sint64 pos)
+{
+ PHYSFS_uint64 ui64;
+ PHYSFS_uint32 ui32;
+ PHYSFS_uint16 ui16;
+ //PHYSFS_sint64 len;
+
+ /* We should be positioned right past the locator signature. */
+
+ if ((pos < 0) || (!io->seek(io, pos)))
+ return 0;
+
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ if (ui32 != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG)
+ return -1; /* it's not a Zip64 archive. Not an error, though! */
+
+ info->zip64 = 1;
+
+ /* number of the disk with the start of the central directory. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* offset of Zip64 end of central directory record. */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* total number of disks */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 1, PHYSFS_ERR_CORRUPT, 0);
+
+ pos = zip64_find_end_of_central_dir(io, pos, ui64);
+ if (pos < 0)
+ return 0; /* oh well. */
+
+ /*
+ * For self-extracting archives, etc, there's crapola in the file
+ * before the zipfile records; we calculate how much data there is
+ * prepended by determining how far the zip64-end-of-central-directory
+ * offset is from where it is supposed to be...the difference in bytes
+ * is how much arbitrary data is at the start of the physical file.
+ */
+ assert(((PHYSFS_uint64) pos) >= ui64);
+ *data_start = ((PHYSFS_uint64) pos) - ui64;
+
+ BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
+
+ /* check signature again, just in case. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != ZIP64_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+ /* size of Zip64 end of central directory record. */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* version made by. */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /* version needed to extract. */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /* number of this disk. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* number of disk with start of central directory record. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* total number of entries in the central dir on this disk */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* total number of entries in the central dir */
+ BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
+ BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
+
+ /* size of the central directory */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* offset of central directory */
+ BAIL_IF_MACRO(!readui64(io, dir_ofs), ERRPASS, 0);
+
+ /* Since we know the difference, fix up the central dir offset... */
+ *dir_ofs += *data_start;
+
+ /*
+ * There are more fields here, for encryption and feature-specific things,
+ * but we don't care about any of them at the moment.
+ */
+
+ return 1; /* made it. */
+} /* zip64_parse_end_of_central_dir */
+
+
static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
- PHYSFS_uint32 *data_start,
- PHYSFS_uint32 *central_dir_ofs)
+ PHYSFS_uint64 *data_start,
+ PHYSFS_uint64 *dir_ofs)
{
+ PHYSFS_uint16 entryCount16;
+ PHYSFS_uint32 offset32;
PHYSFS_uint32 ui32;
PHYSFS_uint16 ui16;
PHYSFS_sint64 len;
PHYSFS_sint64 pos;
+ int rc;
/* find the end-of-central-dir record, and seek to it. */
pos = zip_find_end_of_central_dir(io, &len);
@@ -1041,6 +1321,18 @@
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+ /* Seek back to see if "Zip64 end of central directory locator" exists. */
+ /* this record is 20 bytes before end-of-central-dir */
+ rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
+ BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
+ if (rc == 1)
+ return 1; /* we're done here. */
+
+ assert(rc == -1); /* no error, just not a Zip64 archive. */
+
+ /* Not Zip64? Seek back to where we were and keep processing. */
+ BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
+
/* number of this disk */
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
@@ -1053,15 +1345,16 @@
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
/* total number of entries in the central dir */
- BAIL_IF_MACRO(!readui16(io, &info->entryCount), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
/* size of the central directory */
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
/* offset of central directory */
- BAIL_IF_MACRO(!readui32(io, central_dir_ofs), ERRPASS, 0);
- BAIL_IF_MACRO(pos < *central_dir_ofs + ui32, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(!readui32(io, &offset32), ERRPASS, 0);
+ *dir_ofs = (PHYSFS_uint64) offset32;
+ BAIL_IF_MACRO(pos < (*dir_ofs + ui32), PHYSFS_ERR_CORRUPT, 0);
/*
* For self-extracting archives, etc, there's crapola in the file
@@ -1071,10 +1364,10 @@
* sizeof central dir)...the difference in bytes is how much arbitrary
* data is at the start of the physical file.
*/
- *data_start = (PHYSFS_uint32) (pos - (*central_dir_ofs + ui32));
+ *data_start = (PHYSFS_uint64) (pos - (*dir_ofs + ui32));
/* Now that we know the difference, fix up the central dir offset... */
- *central_dir_ofs += *data_start;
+ *dir_ofs += *data_start;
/* zipfile comment length */
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
@@ -1093,8 +1386,8 @@
static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
ZIPinfo *info = NULL;
- PHYSFS_uint32 data_start;
- PHYSFS_uint32 cent_dir_ofs;
+ PHYSFS_uint64 data_start;
+ PHYSFS_uint64 cent_dir_ofs;
assert(io != NULL); /* shouldn't ever happen. */
@@ -1122,14 +1415,14 @@
} /* ZIP_openArchive */
-static PHYSFS_sint32 zip_find_start_of_dir(ZIPinfo *info, const char *path,
+static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
int stop_on_first_find)
{
- PHYSFS_sint32 lo = 0;
- PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+ PHYSFS_sint64 lo = 0;
+ PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
PHYSFS_sint32 middle;
PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
- PHYSFS_sint32 retval = -1;
+ PHYSFS_sint64 retval = -1;
const char *name;
int rc;
@@ -1198,7 +1491,8 @@
const char *origdir, void *callbackdata)
{
ZIPinfo *info = ((ZIPinfo *) opaque);
- PHYSFS_sint32 dlen, dlen_inc, max, i;
+ PHYSFS_sint32 dlen, dlen_inc;
+ PHYSFS_sint64 i, max;
i = zip_find_start_of_dir(info, dname, 0);
if (i == -1) /* no such directory. */
@@ -1209,7 +1503,7 @@
dlen--;
dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
- max = (PHYSFS_sint32) info->entryCount;
+ max = (PHYSFS_sint64) info->entryCount;
while (i < max)
{
char *e = info->entries[i].name;
@@ -1384,7 +1678,7 @@
else
{
- stat->filesize = entry->uncompressed_size;
+ stat->filesize = (PHYSFS_sint64) entry->uncompressed_size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
} /* else */