Skip to content

Commit

Permalink
Always store all zip64 extension values for maximum compatibility. zl…
Browse files Browse the repository at this point in the history
…ib-ng#543

Update zip64 extension values if not using data descriptor.

Co-authored-by: Vlad Lipskiy <[email protected]>
  • Loading branch information
nmoinvaz and Eswcvlad committed Dec 23, 2020
1 parent 0030fa2 commit ef93d65
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 48 deletions.
20 changes: 13 additions & 7 deletions mz_strm_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,24 @@ static int32_t mz_stream_buffered_flush(void *stream, int32_t *written) {

int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size) {
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int64_t position = 0;
int32_t buf_len = 0;
int32_t bytes_to_read = 0;
int32_t bytes_to_copy = 0;
int32_t bytes_left_to_read = size;
int32_t bytes_read = 0;
int32_t bytes_flushed = 0;

mz_stream_buffered_print("Buffered - Read (size %" PRId32 " pos %" PRId64 ")\n", size, buffered->position);

if (buffered->writebuf_len > 0) {
mz_stream_buffered_print("Buffered - Switch from write to read, not yet supported (pos %" PRId64 ")\n",
mz_stream_buffered_print("Buffered - Switch from write to read, flushing (pos %" PRId64 ")\n",
buffered->position);

position = buffered->position + buffered->writebuf_pos;

mz_stream_buffered_flush(stream, &bytes_flushed);
mz_stream_buffered_seek(stream, position, MZ_SEEK_SET);
}

while (bytes_left_to_read > 0) {
Expand Down Expand Up @@ -264,19 +271,18 @@ int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin) {
switch (origin) {
case MZ_SEEK_SET:

if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
(offset >= buffered->position - buffered->readbuf_len)) {
buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));
return MZ_OK;
}
if (buffered->writebuf_len > 0) {
if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len)) {
buffered->writebuf_pos = (int32_t)(offset - buffered->position);
return MZ_OK;
}
}

if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
(offset >= buffered->position - buffered->readbuf_len)) {
buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));
return MZ_OK;
}

err = mz_stream_buffered_flush(stream, &bytes_flushed);
if (err != MZ_OK)
return err;
Expand Down
109 changes: 68 additions & 41 deletions mz_zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,31 +521,60 @@ static int32_t mz_zip_entry_read_descriptor(void *stream, uint8_t zip64, uint32_
return err;
}

static int32_t mz_zip_entry_write_crc_sizes(void *stream, uint8_t mask, mz_zip_file *file_info) {
static int32_t mz_zip_entry_write_crc_sizes(void *stream, uint8_t zip64, uint8_t mask, mz_zip_file *file_info) {
int32_t err = MZ_OK;

if (mask)
err = mz_stream_write_uint32(stream, 0);
else
err = mz_stream_write_uint32(stream, file_info->crc); /* crc */

/* For backwards-compatibility with older zip applications we set all sizes to UINT32_MAX
* when zip64 is needed, instead of only setting sizes larger than UINT32_MAX. */

if (err == MZ_OK) {
if (file_info->compressed_size >= UINT32_MAX) /* compr size */
if (zip64) /* compr size */
err = mz_stream_write_uint32(stream, UINT32_MAX);
else
err = mz_stream_write_uint32(stream, (uint32_t)file_info->compressed_size);
}
if (err == MZ_OK) {
if (file_info->uncompressed_size >= UINT32_MAX) /* uncompr size */
err = mz_stream_write_uint32(stream, UINT32_MAX);
else if (mask)
if (mask) /* uncompr size */
err = mz_stream_write_uint32(stream, 0);
else if (zip64)
err = mz_stream_write_uint32(stream, UINT32_MAX);
else
err = mz_stream_write_uint32(stream, (uint32_t)file_info->uncompressed_size);
}
return err;
}

static int32_t mz_zip_entry_needs_zip64(mz_zip_file *file_info, uint8_t local, uint8_t *zip64) {
uint8_t needs_zip64 = 0;

if (zip64 == NULL)
return MZ_PARAM_ERROR;

needs_zip64 = (file_info->uncompressed_size >= UINT32_MAX) ||
(file_info->compressed_size >= UINT32_MAX) ||
(file_info->disk_offset >= UINT32_MAX);

if (file_info->zip64 == MZ_ZIP64_AUTO) {
/* If uncompressed size is unknown, assume zip64 for 64-bit data descriptors */
*zip64 = (local && file_info->uncompressed_size == 0) || (needs_zip64);
} else if (file_info->zip64 == MZ_ZIP64_FORCE) {
*zip64 = 1;
} else if (file_info->zip64 == MZ_ZIP64_DISABLE) {
/* Zip64 extension is required to zip file */
if (needs_zip64)
return MZ_PARAM_ERROR;

*zip64 = 0;
}

return MZ_OK;
}

static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_file *file_info) {
uint64_t ntfs_time = 0;
uint32_t reserved = 0;
Expand Down Expand Up @@ -578,26 +607,15 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_fil
if ((local) && (file_info->flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO))
mask = 1;

/* Calculate extra field sizes */
if (file_info->uncompressed_size >= UINT32_MAX)
field_length_zip64 += 8;
if (file_info->compressed_size >= UINT32_MAX)
field_length_zip64 += 8;
if (file_info->disk_offset >= UINT32_MAX)
field_length_zip64 += 8;

if (file_info->zip64 == MZ_ZIP64_AUTO) {
/* If uncompressed size is unknown, assume zip64 for 64-bit data descriptors */
zip64 = (local && file_info->uncompressed_size == 0) || (field_length_zip64 > 0);
} else if (file_info->zip64 == MZ_ZIP64_FORCE) {
zip64 = 1;
} else if (file_info->zip64 == MZ_ZIP64_DISABLE) {
/* Zip64 extension is required to zip file */
if (field_length_zip64 > 0)
return MZ_PARAM_ERROR;
}
/* Determine if zip64 extension is necessary */
err = mz_zip_entry_needs_zip64(file_info, local, &zip64);
if (err != MZ_OK)
return err;

/* Start calculating extra field sizes */
if (zip64) {
field_length_zip64 = 8 + 8 + 8;

extrafield_size += 4;
extrafield_size += field_length_zip64;
}
Expand Down Expand Up @@ -699,7 +717,7 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_fil
}

if (err == MZ_OK)
err = mz_zip_entry_write_crc_sizes(stream, mask, file_info);
err = mz_zip_entry_write_crc_sizes(stream, zip64, mask, file_info);

if (mask) {
snprintf(masked_name, sizeof(masked_name), "%" PRIx32 "_%" PRIx64,
Expand Down Expand Up @@ -738,7 +756,7 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_fil
if (err == MZ_OK)
err = mz_stream_write_uint32(stream, file_info->external_fa);
if (err == MZ_OK) {
if (file_info->disk_offset >= UINT32_MAX)
if (zip64)
err = mz_stream_write_uint32(stream, UINT32_MAX);
else
err = mz_stream_write_uint32(stream, (uint32_t)file_info->disk_offset);
Expand Down Expand Up @@ -783,15 +801,15 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_fil
/* Write ZIP64 extra field */
if ((err == MZ_OK) && (zip64)) {
err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_ZIP64, field_length_zip64);
if ((err == MZ_OK) && (file_info->uncompressed_size >= UINT32_MAX)) {
if (err == MZ_OK) {
if (mask)
err = mz_stream_write_int64(stream, 0);
else
err = mz_stream_write_int64(stream, file_info->uncompressed_size);
}
if ((err == MZ_OK) && (file_info->compressed_size >= UINT32_MAX))
if (err == MZ_OK)
err = mz_stream_write_int64(stream, file_info->compressed_size);
if ((err == MZ_OK) && (file_info->disk_offset >= UINT32_MAX))
if (err == MZ_OK)
err = mz_stream_write_int64(stream, file_info->disk_offset);
}
/* Write NTFS extra field */
Expand Down Expand Up @@ -2091,21 +2109,11 @@ int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compresse
mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size);
}

mz_zip_entry_needs_zip64(&zip->file_info, 1, &zip64);

if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) {
/* Determine if we need to write data descriptor in zip64 format,
if local extrafield was saved with zip64 extrafield */
if (zip->file_info.zip64 == MZ_ZIP64_AUTO) {
if (zip->file_info.uncompressed_size >= UINT32_MAX)
zip64 = 1;
if (zip->file_info.compressed_size >= UINT32_MAX)
zip64 = 1;
if (zip->file_info.disk_offset >= UINT32_MAX)
zip64 = 1;
else if (zip->file_info.uncompressed_size == 0)
zip64 = 1;
} else if (zip->file_info.zip64 == MZ_ZIP64_FORCE) {
zip64 = 1;
}

if (zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO)
err = mz_zip_entry_write_descriptor(zip->stream,
Expand Down Expand Up @@ -2142,7 +2150,26 @@ int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compresse
}

if (err == MZ_OK)
err = mz_zip_entry_write_crc_sizes(zip->stream, 0, &zip->file_info);
err = mz_zip_entry_write_crc_sizes(zip->stream, zip64, 0, &zip->file_info);

/* Seek to and update zip64 extension sizes */
if ((err == MZ_OK) && (zip64) && (zip->file_info.extrafield_size > 0)) {
uint16_t length = 0;
uint64_t filename_size = zip->file_info.filename_size;

if (filename_size == 0 && zip->file_info.filename != NULL)
filename_size = strlen(zip->file_info.filename);

err = mz_stream_seek(zip->stream, 2 + 2 + filename_size, MZ_SEEK_CUR);

if ((err == MZ_OK) && (mz_zip_extrafield_find(zip->stream, MZ_ZIP_EXTENSION_ZIP64, &length) == MZ_OK)) {
if (length >= 8)
err = mz_stream_write_uint64(zip->stream, zip->file_info.compressed_size);
if ((err == MZ_OK) && (length >= 16))
err = mz_stream_write_uint64(zip->stream, zip->file_info.uncompressed_size);
}
}


mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, end_disk_number);
mz_stream_seek(zip->stream, end_pos, MZ_SEEK_SET);
Expand Down

0 comments on commit ef93d65

Please sign in to comment.