improve compatibility with original minizip

* Fix NULL pointer dereference when calling zipOpen*()
  or unzOpen2*() with NULL filefunc table.
* Rename dos_date to dosDate in zip/unzip structures to
  be compatible with original minizip.
* Add tm struct timestamps to zip/unzip structures and
  populate them with the dosDate value for unzip and
  use the value passed into it on zip, if dosDate is
  zero (mimicing original minizip behaviour.)
* Change zipWriteInFileInZip() return value to be a
  status code (ZIP_OK or ZIP_ERRNO) instead of the
  number of bytes written. This way it's minizip
  compatible.
* Add zipCloseFileInZipRaw64() compatibility wrapper.
* Add these compatibility functions:
  unzGetOffset()
  unzGetOffset64()
  unzSetOffset()
  unzSetOffset64()
* Add stub for compatibility: unzGetLocalExtrafield()
  It will always return zero for now.
* Add original minizip types for compatiblity:
  tm_unz, tm_zip, ZPOS64_T
* Add these minizip (non-compatiblity) APIs:
  mz_zip_get_entry()
  mz_zip_goto_entry()
* zipOpenNewFileInZip*() to use the default filename of
  "-" if filename parameter was NULL. For minizip
  compatibility.
* Fix mz_zip_entry_open_int() and mz_zip_entry_read_open()
  failing with MZ_PARAM_ERROR in raw mode
* Add/cleanup some date-related comments
* mz_zip_time_t_to_tm() to clear the `tm` structure in
  case localtime() call failed.
* Fix mz_zip_tm_to_dosdate() to do the date validation
  on the normalized date (the year in particular), not on
  the raw value passed by the caller. This makes it work
  correctly when year is passed as-is, such as 1990.

The reference minizip was the version that comes with
the latest zlib, currently at 1.2.11.
This commit is contained in:
Viktor Szakats 2018-04-22 19:30:34 +00:00
parent ad8e3dd4b1
commit ce26dba5ba
4 changed files with 139 additions and 18 deletions

View File

@ -59,8 +59,16 @@ extern zipFile ZEXPORT zipOpen2_64(const void *path, int append, const char **gl
void *handle = NULL;
void *stream = NULL;
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
if (pzlib_filefunc_def)
{
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
}
else
{
if (mz_stream_os_create(&stream) == NULL)
return NULL;
}
switch (append)
{
@ -115,11 +123,16 @@ extern int ZEXPORT zipOpenNewFileInZip5(zipFile file, const char *filename, cons
if (zipfi != NULL)
{
file_info.modified_date = mz_zip_dosdate_to_time_t(zipfi->dos_date);
file_info.modified_date = mz_zip_dosdate_to_time_t(zipfi->dosDate != 0 ?
zipfi->dosDate :
mz_zip_tm_to_dosdate(&zipfi->tmz_date));
file_info.external_fa = zipfi->external_fa;
file_info.internal_fa = zipfi->internal_fa;
}
if (filename == NULL)
filename = "-";
file_info.compression_method = compression_method;
file_info.filename = (char *)filename;
//file_info.extrafield_local = extrafield_local;
@ -189,10 +202,15 @@ extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void *buf, uint32_t l
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return MZ_PARAM_ERROR;
return mz_zip_entry_write(compat->handle, buf, len);
return mz_zip_entry_write(compat->handle, buf, len) == len ? ZIP_OK : ZIP_ERRNO;
}
extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32)
{
return zipCloseFileInZipRaw64(file, (uint32_t) uncompressed_size, crc32);
}
extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
@ -270,8 +288,16 @@ extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_
void *handle = NULL;
void *stream = NULL;
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
if (pzlib_filefunc_def)
{
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
}
else
{
if (mz_stream_os_create(&stream) == NULL)
return NULL;
}
if (mz_stream_open(stream, path, mode) != MZ_OK)
{
@ -422,6 +448,7 @@ extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info
if (compat == NULL)
return MZ_PARAM_ERROR;
err = mz_zip_entry_get_info(compat->handle, &file_info);
if ((err == MZ_OK) && (pfile_info != NULL))
@ -430,7 +457,9 @@ extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info
pfile_info->version_needed = file_info->version_needed;
pfile_info->flag = file_info->flag;
pfile_info->compression_method = file_info->compression_method;
pfile_info->dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
pfile_info->dosDate = mz_zip_time_t_to_dos_date(file_info->modified_date);
mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
pfile_info->tmu_date.tm_year += 1900;
pfile_info->crc = file_info->crc;
pfile_info->size_filename = file_info->filename_size;
@ -488,7 +517,9 @@ extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile
pfile_info->version_needed = file_info->version_needed;
pfile_info->flag = file_info->flag;
pfile_info->compression_method = file_info->compression_method;
pfile_info->dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
pfile_info->dosDate = mz_zip_time_t_to_dos_date(file_info->modified_date);
mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
pfile_info->tmu_date.tm_year += 1900;
pfile_info->crc = file_info->crc;
pfile_info->size_filename = file_info->filename_size;
@ -557,6 +588,46 @@ extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileName
return mz_zip_locate_entry(compat->handle, filename, filename_compare_func);
}
extern int32_t ZEXPORT unzGetOffset(unzFile file)
{
if (file == NULL)
return UNZ_PARAMERROR;
return (int32_t)unzGetOffset64(file);
}
extern int64_t ZEXPORT unzGetOffset64(unzFile file)
{
if (file == NULL)
return UNZ_PARAMERROR;
return mz_zip_get_entry(((mz_compat *)file)->handle);
}
extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos)
{
return unzSetOffset64(file, pos);
}
extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos)
{
int err = UNZ_OK;
if (file == NULL)
return UNZ_PARAMERROR;
return (int)mz_zip_goto_entry(((mz_compat *)file)->handle, pos);
}
extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) // TODO
{
(void)file;
(void)buf;
(void)len;
return 0;
}
/***************************************************************************/
void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)

View File

@ -79,11 +79,17 @@ typedef void *zlib_filefunc_def;
typedef void *zlib_filefunc64_def;
typedef const char *zipcharpc;
typedef struct tm tm_unz;
typedef struct tm tm_zip;
typedef uint64_t ZPOS64_T;
/***************************************************************************/
typedef struct
{
uint32_t dos_date;
uint32_t dosDate;
struct tm tmz_date;
uint16_t internal_fa; // internal file attributes 2 bytes
uint32_t external_fa; // external file attributes 4 bytes
} zip_fileinfo;
@ -141,6 +147,7 @@ extern int ZEXPORT zipOpenNewFileInZip5(zipFile file, const char *filename, cons
extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len);
extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32);
extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32);
extern int ZEXPORT zipCloseFileInZip(zipFile file);
extern int ZEXPORT zipCloseFileInZip64(zipFile file);
@ -193,7 +200,8 @@ typedef struct unz_file_info64_s
uint16_t version_needed; // version needed to extract 2 bytes
uint16_t flag; // general purpose bit flag 2 bytes
uint16_t compression_method; // compression method 2 bytes
uint32_t dos_date; // last mod file date in Dos fmt 4 bytes
uint32_t dosDate; // last mod file date in Dos fmt 4 bytes
struct tm tmu_date;
uint32_t crc; // crc-32 4 bytes
uint64_t compressed_size; // compressed size 8 bytes
uint64_t uncompressed_size; // uncompressed size 8 bytes
@ -216,7 +224,8 @@ typedef struct unz_file_info_s
uint16_t version_needed; // version needed to extract 2 bytes
uint16_t flag; // general purpose bit flag 2 bytes
uint16_t compression_method; // compression method 2 bytes
uint32_t dos_date; // last mod file date in Dos fmt 4 bytes
uint32_t dosDate; // last mod file date in Dos fmt 4 bytes
struct tm tmu_date;
uint32_t crc; // crc-32 4 bytes
uint32_t compressed_size; // compressed size 4 bytes
uint32_t uncompressed_size; // uncompressed size 4 bytes
@ -264,6 +273,12 @@ extern int ZEXPORT unzGoToFirstFile(unzFile file);
extern int ZEXPORT unzGoToNextFile(unzFile file);
extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
extern int64_t ZEXPORT unzGetOffset64(unzFile file);
extern int32_t ZEXPORT unzGetOffset(unzFile file);
extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos);
extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos);
extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len);
/***************************************************************************/
void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);

View File

@ -1073,10 +1073,10 @@ static int32_t mz_zip_entry_open_int(void *handle, int16_t compression_method, i
return MZ_PARAM_ERROR;
}
if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL))
if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) && zip->compression_method != MZ_COMPRESS_METHOD_RAW)
return MZ_PARAM_ERROR;
if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED))
if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && zip->compression_method != MZ_COMPRESS_METHOD_RAW)
{
#ifdef HAVE_AES
if (zip->file_info.aes_version)
@ -1215,7 +1215,7 @@ extern int32_t mz_zip_entry_read_open(void *handle, int16_t raw, const char *pas
return MZ_PARAM_ERROR;
if (zip->entry_scanned == 0)
return MZ_PARAM_ERROR;
if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL))
if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) && !raw)
return MZ_PARAM_ERROR;
if (zip->file_info.disk_number == zip->disk_number_with_cd)
@ -1476,6 +1476,31 @@ extern int32_t mz_zip_get_disk_number_with_cd(void *handle, int32_t *disk_number
return MZ_OK;
}
extern int64_t mz_zip_get_entry(void *handle)
{
mz_zip *zip = (mz_zip *)handle;
if (zip == NULL)
return MZ_PARAM_ERROR;
return zip->cd_current_pos;
}
extern int32_t mz_zip_goto_entry(void *handle, uint64_t cd_pos)
{
mz_zip *zip = (mz_zip *)handle;
if (zip == NULL)
return MZ_PARAM_ERROR;
if (cd_pos < zip->cd_start_pos || cd_pos > zip->cd_start_pos + zip->cd_size)
return MZ_PARAM_ERROR;
zip->cd_current_pos = cd_pos;
return mz_zip_goto_next_entry_int(handle);
}
extern int32_t mz_zip_goto_first_entry(void *handle)
{
mz_zip *zip = (mz_zip *)handle;
@ -1532,7 +1557,7 @@ extern int32_t mz_zip_locate_entry(void *handle, const char *filename, mz_filena
static int32_t mz_zip_invalid_date(const struct tm *ptm)
{
#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max))
return (!datevalue_in_range(0, 207, ptm->tm_year) ||
return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) || // 1980-based year, allow 80 extra
!datevalue_in_range(0, 11, ptm->tm_mon) ||
!datevalue_in_range(1, 31, ptm->tm_mday) ||
!datevalue_in_range(0, 23, ptm->tm_hour) ||
@ -1582,9 +1607,13 @@ int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm)
struct tm *ltm = NULL;
if (ptm == NULL)
return MZ_PARAM_ERROR;
ltm = localtime(&unix_time);
ltm = localtime(&unix_time); // Returns a 1900-based year
if (ltm == NULL)
{
// Invalid date stored, so don't return it
memset(ptm, 0, sizeof(struct tm));
return MZ_INTERNAL_ERROR;
}
memcpy(ptm, ltm, sizeof(struct tm));
return MZ_OK;
}
@ -1610,12 +1639,12 @@ uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm)
memcpy(&fixed_tm, ptm, sizeof(struct tm));
if (fixed_tm.tm_year >= 1980) // range [1980, 2107]
fixed_tm.tm_year -= 1980;
else if (fixed_tm.tm_year >= 80) // range [80, 99]
else if (fixed_tm.tm_year >= 80) // range [80, 207]
fixed_tm.tm_year -= 80;
else // range [00, 79]
fixed_tm.tm_year += 20;
if (mz_zip_invalid_date(ptm))
if (mz_zip_invalid_date(&fixed_tm))
return 0;
return (uint32_t)(((fixed_tm.tm_mday) + (32 * (fixed_tm.tm_mon + 1)) + (512 * fixed_tm.tm_year)) << 16) |

View File

@ -111,6 +111,12 @@ extern int32_t mz_zip_get_number_entry(void *handle, int64_t *number_entry);
extern int32_t mz_zip_get_disk_number_with_cd(void *handle, int32_t *disk_number_with_cd);
// Get the the disk number containing the central directory record
extern int64_t mz_zip_get_entry(void *handle);
// Return offset of the current entry in the zip file
extern int32_t mz_zip_goto_entry(void *handle, uint64_t cd_pos);
// Go to specified entry in the zip file
extern int32_t mz_zip_goto_first_entry(void *handle);
// Go to the first entry in the zip file