mirror of
https://github.com/zlib-ng/minizip-ng
synced 2025-03-28 21:13:18 +00:00

Allow greater buffer to be passed in for hashing functions. Fixed crc32 values not being stored in zip. When reading zip get best hash to test against in signature. Fixed formatting.
1896 lines
55 KiB
C
1896 lines
55 KiB
C
/* mz_zip_rw.c -- Zip reader/writer
|
|
Version 2.6.0, October 8, 2018
|
|
part of the MiniZip project
|
|
|
|
Copyright (C) 2010-2018 Nathan Moinvaziri
|
|
https://github.com/nmoinvaz/minizip
|
|
|
|
This program is distributed under the terms of the same license as zlib.
|
|
See the accompanying LICENSE file for the full text of the license.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#include "mz.h"
|
|
#include "mz_crypt.h"
|
|
#include "mz_os.h"
|
|
#include "mz_strm.h"
|
|
#include "mz_strm_buf.h"
|
|
#include "mz_strm_mem.h"
|
|
#include "mz_strm_os.h"
|
|
#include "mz_strm_split.h"
|
|
#include "mz_strm_wzaes.h"
|
|
#include "mz_zip.h"
|
|
|
|
#include "mz_zip_rw.h"
|
|
|
|
/***************************************************************************/
|
|
|
|
#define MZ_DEFAULT_PROGRESS_INTERVAL (1000u)
|
|
|
|
#define MZ_ZIP_CD_FILENAME ("__cdcd__")
|
|
|
|
/***************************************************************************/
|
|
|
|
typedef struct mz_zip_reader_s {
|
|
void *zip_handle;
|
|
void *file_stream;
|
|
void *buffered_stream;
|
|
void *split_stream;
|
|
void *mem_stream;
|
|
void *hash;
|
|
uint16_t hash_algorithm;
|
|
uint16_t hash_digest_size;
|
|
mz_zip_file *file_info;
|
|
const char *pattern;
|
|
uint8_t pattern_ignore_case;
|
|
const char *password;
|
|
void *overwrite_userdata;
|
|
mz_zip_reader_overwrite_cb
|
|
overwrite_cb;
|
|
void *password_userdata;
|
|
mz_zip_reader_password_cb
|
|
password_cb;
|
|
void *progress_userdata;
|
|
mz_zip_reader_progress_cb
|
|
progress_cb;
|
|
uint32_t progress_cb_interval_ms;
|
|
void *entry_userdata;
|
|
mz_zip_reader_entry_cb
|
|
entry_cb;
|
|
uint8_t raw;
|
|
uint8_t buffer[UINT16_MAX];
|
|
uint8_t legacy_encoding;
|
|
} mz_zip_reader;
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_reader_is_open(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
if (reader == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->zip_handle == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
return MZ_OK;
|
|
}
|
|
|
|
int32_t mz_zip_reader_open(void *handle, void *stream)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
mz_zip_create(&reader->zip_handle);
|
|
err = mz_zip_open(reader->zip_handle, stream, MZ_OPEN_MODE_READ);
|
|
|
|
if (err != MZ_OK)
|
|
{
|
|
mz_zip_reader_close(handle);
|
|
return MZ_STREAM_ERROR;
|
|
}
|
|
|
|
return MZ_OK;
|
|
}
|
|
|
|
int32_t mz_zip_reader_open_file(void *handle, const char *path)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
mz_zip_reader_close(handle);
|
|
|
|
mz_stream_os_create(&reader->file_stream);
|
|
mz_stream_buffered_create(&reader->buffered_stream);
|
|
mz_stream_split_create(&reader->split_stream);
|
|
|
|
mz_stream_set_base(reader->buffered_stream, reader->file_stream);
|
|
mz_stream_set_base(reader->split_stream, reader->buffered_stream);
|
|
|
|
err = mz_stream_open(reader->split_stream, path, MZ_OPEN_MODE_READ);
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_open(handle, reader->split_stream);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_stream = NULL;
|
|
int64_t file_size = 0;
|
|
int32_t err = 0;
|
|
|
|
|
|
mz_zip_reader_close(handle);
|
|
|
|
mz_stream_os_create(&file_stream);
|
|
|
|
err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
|
|
|
|
if (err != MZ_OK)
|
|
{
|
|
mz_stream_os_delete(&file_stream);
|
|
mz_zip_reader_close(handle);
|
|
return err;
|
|
}
|
|
|
|
mz_stream_os_seek(file_stream, 0, SEEK_END);
|
|
file_size = mz_stream_os_tell(file_stream);
|
|
mz_stream_os_seek(file_stream, 0, SEEK_SET);
|
|
|
|
if ((file_size <= 0) || (file_size > UINT32_MAX))
|
|
{
|
|
// Memory size is too large or too small
|
|
|
|
mz_stream_os_close(file_stream);
|
|
mz_stream_os_delete(&file_stream);
|
|
mz_zip_reader_close(handle);
|
|
return MZ_MEM_ERROR;
|
|
}
|
|
|
|
mz_stream_mem_create(&reader->mem_stream);
|
|
mz_stream_mem_set_grow_size(reader->mem_stream, (int32_t)file_size);
|
|
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
|
|
err = mz_stream_copy(reader->mem_stream, file_stream, (int32_t)file_size);
|
|
|
|
mz_stream_os_close(file_stream);
|
|
mz_stream_os_delete(&file_stream);
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_open(handle, reader->mem_stream);
|
|
if (err != MZ_OK)
|
|
mz_zip_reader_close(handle);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
mz_zip_reader_close(handle);
|
|
|
|
mz_stream_mem_create(&reader->mem_stream);
|
|
|
|
if (copy)
|
|
{
|
|
mz_stream_mem_set_grow_size(reader->mem_stream, len);
|
|
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
mz_stream_mem_write(reader->mem_stream, buf, len);
|
|
mz_stream_mem_seek(reader->mem_stream, 0, SEEK_SET);
|
|
}
|
|
else
|
|
{
|
|
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_READ);
|
|
mz_stream_mem_set_buffer(reader->mem_stream, buf, len);
|
|
}
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_open(handle, reader->mem_stream);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_close(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (reader->zip_handle != NULL)
|
|
{
|
|
err = mz_zip_close(reader->zip_handle);
|
|
mz_zip_delete(&reader->zip_handle);
|
|
}
|
|
|
|
if (reader->split_stream != NULL)
|
|
{
|
|
mz_stream_split_close(reader->split_stream);
|
|
mz_stream_split_delete(&reader->split_stream);
|
|
}
|
|
|
|
if (reader->buffered_stream != NULL)
|
|
mz_stream_buffered_delete(&reader->buffered_stream);
|
|
|
|
if (reader->file_stream != NULL)
|
|
mz_stream_os_delete(&reader->file_stream);
|
|
|
|
if (reader->mem_stream != NULL)
|
|
{
|
|
mz_stream_mem_close(reader->mem_stream);
|
|
mz_stream_mem_delete(&reader->mem_stream);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_reader_unzip_cd(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
mz_zip_file *cd_info = NULL;
|
|
void *cd_mem_stream = NULL;
|
|
void *new_cd_stream = NULL;
|
|
void *file_extra_stream = NULL;
|
|
uint64_t number_entry = 0;
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
err = mz_zip_reader_goto_first_entry(handle);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
err = mz_zip_reader_entry_get_info(handle, &cd_info);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
if (strcmp(cd_info->filename, MZ_ZIP_CD_FILENAME) != 0)
|
|
return mz_zip_reader_goto_first_entry(handle);
|
|
|
|
err = mz_zip_reader_entry_open(handle);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_set_buffer(file_extra_stream, (void *)cd_info->extrafield, cd_info->extrafield_size);
|
|
|
|
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, NULL);
|
|
if (err == MZ_OK)
|
|
err = mz_stream_read_uint64(file_extra_stream, &number_entry);
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream);
|
|
if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK)
|
|
mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
|
|
err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read,
|
|
(int32_t)cd_info->uncompressed_size);
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream);
|
|
mz_zip_set_number_entry(reader->zip_handle, number_entry);
|
|
err = mz_zip_reader_goto_first_entry(handle);
|
|
}
|
|
|
|
mz_stream_mem_delete(&new_cd_stream);
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
static int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)userdata;
|
|
int32_t result = 0;
|
|
MZ_UNUSED(handle);
|
|
result = mz_path_compare_wc(file_info->filename, reader->pattern, reader->pattern_ignore_case);
|
|
return result;
|
|
}
|
|
|
|
int32_t mz_zip_reader_goto_first_entry(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_reader_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
|
|
mz_zip_reader_entry_close(handle);
|
|
|
|
if (reader->pattern == NULL)
|
|
err = mz_zip_goto_first_entry(reader->zip_handle);
|
|
else
|
|
err = mz_zip_locate_first_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
|
|
|
|
reader->file_info = NULL;
|
|
if (err == MZ_OK)
|
|
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_goto_next_entry(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_reader_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
|
|
mz_zip_reader_entry_close(handle);
|
|
|
|
if (reader->pattern == NULL)
|
|
err = mz_zip_goto_next_entry(reader->zip_handle);
|
|
else
|
|
err = mz_zip_locate_next_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
|
|
|
|
reader->file_info = NULL;
|
|
if (err == MZ_OK)
|
|
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
|
|
mz_zip_reader_entry_close(handle);
|
|
|
|
err = mz_zip_locate_entry(reader->zip_handle, filename, ignore_case);
|
|
|
|
reader->file_info = NULL;
|
|
if (err == MZ_OK)
|
|
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_reader_entry_open(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
const char *password = NULL;
|
|
char password_buf[120];
|
|
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// If the entry isn't open for reading, open it
|
|
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
|
|
return MZ_OK;
|
|
|
|
password = reader->password;
|
|
|
|
// Check if we need a password and ask for it if we need to
|
|
if ((reader->file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
|
|
(reader->password_cb != NULL))
|
|
{
|
|
reader->password_cb(handle, reader->password_userdata, reader->file_info,
|
|
password_buf, sizeof(password_buf));
|
|
|
|
password = password_buf;
|
|
}
|
|
|
|
err = mz_zip_entry_read_open(reader->zip_handle, reader->raw, password);
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
if (err != MZ_OK)
|
|
return err;
|
|
if (mz_zip_reader_entry_get_best_hash(handle, &reader->hash_algorithm, &reader->hash_digest_size) == MZ_OK)
|
|
{
|
|
mz_crypt_sha_create(&reader->hash);
|
|
if (reader->hash_algorithm == MZ_HASH_SHA1)
|
|
mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA1);
|
|
else if (reader->hash_algorithm == MZ_HASH_SHA256)
|
|
mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA256);
|
|
else
|
|
err = MZ_SUPPORT_ERROR;
|
|
|
|
if (err == MZ_OK)
|
|
mz_crypt_sha_begin(reader->hash);
|
|
#ifndef MZ_ZIP_NO_SIGNING
|
|
if ((err == MZ_OK) && (mz_zip_reader_entry_has_sign(handle) == MZ_OK))
|
|
err = mz_zip_reader_entry_sign_verify(handle);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_close(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
int32_t err_close = MZ_OK;
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
int32_t err_hash = MZ_OK;
|
|
uint8_t computed_hash[MZ_HASH_MAX_SIZE];
|
|
uint8_t expected_hash[MZ_HASH_MAX_SIZE];
|
|
|
|
if (reader->hash != NULL)
|
|
{
|
|
mz_crypt_sha_end(reader->hash, computed_hash, sizeof(computed_hash));
|
|
mz_crypt_sha_delete(&reader->hash);
|
|
|
|
err_hash = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, expected_hash,
|
|
reader->hash_digest_size);
|
|
|
|
if (err_hash == MZ_OK)
|
|
{
|
|
// Verify expected hash against computed hash
|
|
if (memcmp(computed_hash, expected_hash, reader->hash_digest_size) != 0)
|
|
err = MZ_CRC_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
err_close = mz_zip_entry_close(reader->zip_handle);
|
|
if (err == MZ_OK)
|
|
err = err_close;
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t read = 0;
|
|
read = mz_zip_entry_read(reader->zip_handle, buf, len);
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
if ((read > 0) && (reader->hash != NULL))
|
|
mz_crypt_sha_update(reader->hash, buf, read);
|
|
#endif
|
|
return read;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_has_sign(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_extra_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
|
|
reader->file_info->extrafield_size);
|
|
|
|
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, NULL);
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
return err;
|
|
}
|
|
|
|
#if !defined(MZ_ZIP_NO_ENCRYPTION) && !defined(MZ_ZIP_NO_SIGNING)
|
|
int32_t mz_zip_reader_entry_sign_verify(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_extra_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
uint8_t *signature = NULL;
|
|
uint16_t signature_size = 0;
|
|
uint8_t hash[MZ_HASH_MAX_SIZE];
|
|
|
|
if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
|
|
reader->file_info->extrafield_size);
|
|
|
|
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, &signature_size);
|
|
if ((err == MZ_OK) && (signature_size > 0))
|
|
{
|
|
signature = (uint8_t *)MZ_ALLOC(signature_size);
|
|
if (mz_stream_read(file_extra_stream, signature, signature_size) != signature_size)
|
|
err = MZ_STREAM_ERROR;
|
|
}
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
// Get most secure hash to verify signature against
|
|
err = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, hash, reader->hash_digest_size);
|
|
}
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
// Verify the pkcs signature
|
|
err = mz_crypt_sign_verify(hash, reader->hash_digest_size, signature, signature_size);
|
|
}
|
|
|
|
if (signature != NULL)
|
|
MZ_FREE(signature);
|
|
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_extra_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
int32_t return_err = MZ_EXIST_ERROR;
|
|
uint16_t cur_algorithm = 0;
|
|
uint16_t cur_digest_size = 0;
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
|
|
reader->file_info->extrafield_size);
|
|
|
|
do
|
|
{
|
|
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, NULL);
|
|
if (err != MZ_OK)
|
|
break;
|
|
|
|
err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
|
|
if (err == MZ_OK)
|
|
err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
|
|
if ((cur_algorithm == algorithm) && (cur_digest_size <= digest_size) &&
|
|
(cur_digest_size <= MZ_HASH_MAX_SIZE))
|
|
{
|
|
// Read hash digest
|
|
if (mz_stream_read(file_extra_stream, digest, digest_size) != cur_digest_size)
|
|
err = MZ_FORMAT_ERROR;
|
|
else
|
|
return_err = MZ_OK;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
err = mz_stream_seek(file_extra_stream, cur_digest_size, SEEK_CUR);
|
|
}
|
|
}
|
|
while (err == MZ_OK);
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
return return_err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_get_best_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_extra_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
int32_t return_err = MZ_EXIST_ERROR;
|
|
uint16_t last_algorithm = 0;
|
|
uint16_t cur_algorithm = 0;
|
|
uint16_t cur_digest_size = 0;
|
|
|
|
if (reader == NULL || algorithm == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
|
|
reader->file_info->extrafield_size);
|
|
|
|
do
|
|
{
|
|
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, NULL);
|
|
if (err != MZ_OK)
|
|
break;
|
|
|
|
err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
|
|
if (err == MZ_OK)
|
|
err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
|
|
|
|
if ((cur_algorithm > last_algorithm) && (cur_digest_size <= MZ_HASH_MAX_SIZE))
|
|
{
|
|
last_algorithm = cur_algorithm;
|
|
if (algorithm != NULL)
|
|
*algorithm = cur_algorithm;
|
|
if (digest_size != NULL)
|
|
*digest_size = cur_digest_size;
|
|
|
|
return_err = MZ_OK;
|
|
}
|
|
|
|
err = mz_stream_seek(file_extra_stream, cur_digest_size, SEEK_CUR);
|
|
}
|
|
while (err == MZ_OK);
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
if (return_err != MZ_OK)
|
|
{
|
|
if (digest_size != NULL)
|
|
*digest_size = 0;
|
|
if (algorithm != NULL)
|
|
*algorithm = 0;
|
|
}
|
|
|
|
return return_err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
if (file_info == NULL || mz_zip_reader_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
*file_info = reader->file_info;
|
|
if (*file_info == NULL)
|
|
return MZ_EXIST_ERROR;
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_is_dir(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
if (mz_zip_reader_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
return mz_zip_entry_is_dir(reader->zip_handle);
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
int32_t read = 0;
|
|
int32_t written = 0;
|
|
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
if (write_cb == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// If the entry isn't open for reading, open it
|
|
if (mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
|
|
err = mz_zip_reader_entry_open(handle);
|
|
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
// Unzip entry in zip file
|
|
read = mz_zip_reader_entry_read(handle, reader->buffer, sizeof(reader->buffer));
|
|
|
|
if (read == 0)
|
|
{
|
|
// If we are done close the entry
|
|
err = mz_zip_reader_entry_close(handle);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
return MZ_END_OF_STREAM;
|
|
}
|
|
|
|
if (read > 0)
|
|
{
|
|
// Write the data to the specified stream
|
|
written = write_cb(stream, reader->buffer, read);
|
|
if (written != read)
|
|
return MZ_STREAM_ERROR;
|
|
}
|
|
|
|
return read;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
uint64_t current_time = 0;
|
|
uint64_t update_time = 0;
|
|
int64_t current_pos = 0;
|
|
int64_t update_pos = 0;
|
|
int32_t err = MZ_OK;
|
|
int32_t written = 0;
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// Update the progress at the beginning
|
|
if (reader->progress_cb != NULL)
|
|
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
|
|
|
|
// Write data to stream until done
|
|
while (err == MZ_OK)
|
|
{
|
|
written = mz_zip_reader_entry_save_process(handle, stream, write_cb);
|
|
if (written == MZ_END_OF_STREAM)
|
|
break;
|
|
if (written > 0)
|
|
current_pos += written;
|
|
if (written < 0)
|
|
err = written;
|
|
|
|
// Update progress if enough time have passed
|
|
current_time = mz_os_ms_time();
|
|
if ((current_time - update_time) > reader->progress_cb_interval_ms)
|
|
{
|
|
if (reader->progress_cb != NULL)
|
|
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
|
|
|
|
update_pos = current_pos;
|
|
update_time = current_time;
|
|
}
|
|
}
|
|
|
|
// Update the progress at the end
|
|
if (reader->progress_cb != NULL && update_pos != current_pos)
|
|
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_save_file(void *handle, const char *path)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *file_stream = NULL;
|
|
uint32_t target_attrib = 0;
|
|
int32_t err_attrib = 0;
|
|
int32_t err = MZ_OK;
|
|
int32_t err_cb = MZ_OK;
|
|
char directory[512];
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL || path == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
if (reader->entry_cb != NULL)
|
|
reader->entry_cb(handle, reader->entry_userdata, reader->file_info, path);
|
|
|
|
strncpy(directory, path, sizeof(directory) - 1);
|
|
directory[sizeof(directory) - 1] = 0;
|
|
mz_path_remove_filename(directory);
|
|
|
|
// If it is a directory entry then create a directory instead of writing file
|
|
if (mz_zip_entry_is_dir(reader->zip_handle) == MZ_OK)
|
|
{
|
|
err = mz_dir_make(directory);
|
|
return err;
|
|
}
|
|
|
|
// Check if file exists and ask if we want to overwrite
|
|
if ((mz_os_file_exists(path) == MZ_OK) && (reader->overwrite_cb != NULL))
|
|
{
|
|
err_cb = reader->overwrite_cb(handle, reader->overwrite_userdata, reader->file_info, path);
|
|
if (err_cb != MZ_OK)
|
|
return err;
|
|
mz_os_delete(path);
|
|
}
|
|
|
|
// Create the output directory if it doesn't already exist
|
|
if (mz_os_is_dir(directory) != MZ_OK)
|
|
{
|
|
err = mz_dir_make(directory);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
}
|
|
|
|
mz_stream_os_create(&file_stream);
|
|
|
|
// Create the file on disk so we can save to it
|
|
err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_CREATE);
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_entry_save(handle, file_stream, mz_stream_os_write);
|
|
|
|
mz_stream_os_close(file_stream);
|
|
mz_stream_os_delete(&file_stream);
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
// Set the time of the file that has been created
|
|
mz_os_set_file_date(path, reader->file_info->modified_date,
|
|
reader->file_info->accessed_date, reader->file_info->creation_date);
|
|
}
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
// Set file attributes for the correct system
|
|
err_attrib = mz_zip_attrib_convert(MZ_HOST_SYSTEM(reader->file_info->version_madeby),
|
|
reader->file_info->external_fa, MZ_VERSION_MADEBY_HOST_SYSTEM, &target_attrib);
|
|
|
|
if (err_attrib == MZ_OK)
|
|
mz_os_set_file_attribs(path, target_attrib);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
void *mem_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info->uncompressed_size > INT32_MAX)
|
|
return MZ_PARAM_ERROR;
|
|
if (len != (int32_t)reader->file_info->uncompressed_size)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// Create a memory stream backed by our buffer and save to it
|
|
mz_stream_mem_create(&mem_stream);
|
|
mz_stream_mem_set_buffer(mem_stream, buf, len);
|
|
|
|
err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_entry_save(handle, mem_stream, mz_stream_mem_write);
|
|
|
|
mz_stream_mem_delete(&mem_stream);
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_reader_entry_save_buffer_length(void *handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
if (reader->file_info->uncompressed_size > INT32_MAX)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// Get the maximum size required for the save buffer
|
|
return (int32_t)reader->file_info->uncompressed_size;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
int32_t err = MZ_OK;
|
|
char path[512];
|
|
char utf8_name[256];
|
|
char resolved_name[256];
|
|
|
|
err = mz_zip_reader_goto_first_entry(handle);
|
|
|
|
while (err == MZ_OK)
|
|
{
|
|
// Construct output path
|
|
path[0] = 0;
|
|
|
|
if ((reader->legacy_encoding) && (reader->file_info->flag & MZ_ZIP_FLAG_UTF8) == 0)
|
|
{
|
|
mz_zip_encoding_cp437_to_utf8(reader->file_info->filename, utf8_name, sizeof(utf8_name));
|
|
}
|
|
else
|
|
{
|
|
strncpy(utf8_name, reader->file_info->filename, sizeof(utf8_name) - 1);
|
|
utf8_name[sizeof(utf8_name) - 1] = 0;
|
|
}
|
|
|
|
err = mz_path_resolve(utf8_name, resolved_name, sizeof(resolved_name));
|
|
if (err != MZ_OK)
|
|
break;
|
|
|
|
if (destination_dir != NULL)
|
|
mz_path_combine(path, destination_dir, sizeof(path));
|
|
|
|
mz_path_combine(path, resolved_name, sizeof(path));
|
|
|
|
// Save file to disk
|
|
err = mz_zip_reader_entry_save_file(handle, path);
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_reader_goto_next_entry(handle);
|
|
}
|
|
|
|
if (err == MZ_END_OF_LIST)
|
|
return MZ_OK;
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->pattern = pattern;
|
|
reader->pattern_ignore_case = ignore_case;
|
|
}
|
|
|
|
void mz_zip_reader_set_password(void *handle, const char *password)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->password = password;
|
|
}
|
|
|
|
void mz_zip_reader_set_raw(void *handle, uint8_t raw)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->raw = raw;
|
|
}
|
|
|
|
int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
if (raw == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
*raw = reader->raw;
|
|
return MZ_OK;
|
|
}
|
|
|
|
void mz_zip_reader_set_legacy_encoding(void *handle, uint8_t legacy_encoding)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->legacy_encoding = legacy_encoding;
|
|
}
|
|
|
|
void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->overwrite_cb = cb;
|
|
reader->overwrite_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->password_cb = cb;
|
|
reader->password_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->progress_cb = cb;
|
|
reader->progress_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->progress_cb_interval_ms = milliseconds;
|
|
}
|
|
|
|
void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
reader->entry_cb = cb;
|
|
reader->entry_userdata = userdata;
|
|
}
|
|
|
|
int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle)
|
|
{
|
|
mz_zip_reader *reader = (mz_zip_reader *)handle;
|
|
if (zip_handle == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
*zip_handle = reader->zip_handle;
|
|
if (*zip_handle == NULL)
|
|
return MZ_EXIST_ERROR;
|
|
return MZ_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void *mz_zip_reader_create(void **handle)
|
|
{
|
|
mz_zip_reader *reader = NULL;
|
|
|
|
reader = (mz_zip_reader *)MZ_ALLOC(sizeof(mz_zip_reader));
|
|
if (reader != NULL)
|
|
{
|
|
memset(reader, 0, sizeof(mz_zip_reader));
|
|
reader->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
|
|
*handle = reader;
|
|
}
|
|
|
|
return reader;
|
|
}
|
|
|
|
void mz_zip_reader_delete(void **handle)
|
|
{
|
|
mz_zip_reader *reader = NULL;
|
|
if (handle == NULL)
|
|
return;
|
|
reader = (mz_zip_reader *)*handle;
|
|
if (reader != NULL)
|
|
{
|
|
mz_zip_reader_close(reader);
|
|
MZ_FREE(reader);
|
|
}
|
|
*handle = NULL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
typedef struct mz_zip_writer_s {
|
|
void *zip_handle;
|
|
void *file_stream;
|
|
void *buffered_stream;
|
|
void *split_stream;
|
|
void *sha256;
|
|
void *mem_stream;
|
|
void *file_extra_stream;
|
|
mz_zip_file file_info;
|
|
void *overwrite_userdata;
|
|
mz_zip_writer_overwrite_cb
|
|
overwrite_cb;
|
|
void *password_userdata;
|
|
mz_zip_writer_password_cb
|
|
password_cb;
|
|
void *progress_userdata;
|
|
mz_zip_writer_progress_cb
|
|
progress_cb;
|
|
uint32_t progress_cb_interval_ms;
|
|
void *entry_userdata;
|
|
mz_zip_writer_entry_cb
|
|
entry_cb;
|
|
const char *password;
|
|
const char *cert_path;
|
|
const char *cert_pwd;
|
|
uint16_t compress_method;
|
|
int16_t compress_level;
|
|
int32_t flags;
|
|
uint8_t aes;
|
|
uint8_t raw;
|
|
uint8_t buffer[UINT16_MAX];
|
|
} mz_zip_writer;
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_writer_is_open(void *handle)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
if (writer == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
if (writer->zip_handle == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
return MZ_OK;
|
|
}
|
|
|
|
static int32_t mz_zip_writer_open_int(void *handle, void *stream, int32_t mode)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
mz_zip_create(&writer->zip_handle);
|
|
err = mz_zip_open(writer->zip_handle, stream, mode);
|
|
|
|
if (err != MZ_OK)
|
|
{
|
|
mz_zip_writer_close(handle);
|
|
return MZ_STREAM_ERROR;
|
|
}
|
|
|
|
return MZ_OK;
|
|
}
|
|
|
|
int32_t mz_zip_writer_open(void *handle, void *stream)
|
|
{
|
|
return mz_zip_writer_open_int(handle, stream, 0);
|
|
}
|
|
|
|
int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t mode = MZ_OPEN_MODE_READWRITE;
|
|
int32_t err = MZ_OK;
|
|
int32_t err_cb = 0;
|
|
|
|
|
|
mz_zip_writer_close(handle);
|
|
|
|
if (mz_os_file_exists(path) != MZ_OK)
|
|
{
|
|
// If the file doesn't exist, we don't append file
|
|
mode |= MZ_OPEN_MODE_CREATE;
|
|
}
|
|
else if (append)
|
|
{
|
|
mode |= MZ_OPEN_MODE_APPEND;
|
|
}
|
|
else
|
|
{
|
|
if (writer->overwrite_cb != NULL)
|
|
err_cb = writer->overwrite_cb(handle, writer->overwrite_userdata, path);
|
|
|
|
if (err_cb == MZ_INTERNAL_ERROR)
|
|
return err;
|
|
|
|
if (err_cb == MZ_OK)
|
|
mode |= MZ_OPEN_MODE_CREATE;
|
|
else
|
|
mode |= MZ_OPEN_MODE_APPEND;
|
|
}
|
|
|
|
mz_stream_os_create(&writer->file_stream);
|
|
mz_stream_buffered_create(&writer->buffered_stream);
|
|
mz_stream_split_create(&writer->split_stream);
|
|
|
|
mz_stream_set_base(writer->buffered_stream, writer->file_stream);
|
|
mz_stream_set_base(writer->split_stream, writer->buffered_stream);
|
|
|
|
mz_stream_split_set_prop_int64(writer->split_stream, MZ_STREAM_PROP_DISK_SIZE, disk_size);
|
|
|
|
err = mz_stream_open(writer->split_stream, path, mode);
|
|
if (err == MZ_OK)
|
|
err = mz_zip_writer_open_int(handle, writer->split_stream, mode);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
void *file_stream = NULL;
|
|
int64_t file_size = 0;
|
|
int32_t err = 0;
|
|
|
|
|
|
mz_zip_writer_close(handle);
|
|
|
|
mz_stream_os_create(&file_stream);
|
|
|
|
err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
|
|
|
|
if (err != MZ_OK)
|
|
{
|
|
mz_stream_os_delete(&file_stream);
|
|
mz_zip_writer_close(handle);
|
|
return err;
|
|
}
|
|
|
|
mz_stream_os_seek(file_stream, 0, SEEK_END);
|
|
file_size = mz_stream_os_tell(file_stream);
|
|
mz_stream_os_seek(file_stream, 0, SEEK_SET);
|
|
|
|
if ((file_size <= 0) || (file_size > UINT32_MAX))
|
|
{
|
|
// Memory size is too large or too small
|
|
|
|
mz_stream_os_close(file_stream);
|
|
mz_stream_os_delete(&file_stream);
|
|
mz_zip_writer_close(handle);
|
|
return MZ_MEM_ERROR;
|
|
}
|
|
|
|
mz_stream_mem_create(&writer->mem_stream);
|
|
mz_stream_mem_set_grow_size(writer->mem_stream, (int32_t)file_size);
|
|
mz_stream_mem_open(writer->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
|
|
err = mz_stream_copy(writer->mem_stream, file_stream, (int32_t)file_size);
|
|
|
|
mz_stream_os_close(file_stream);
|
|
mz_stream_os_delete(&file_stream);
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_writer_open(handle, writer->mem_stream);
|
|
if (err != MZ_OK)
|
|
mz_zip_writer_close(handle);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_close(void *handle)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (writer->zip_handle != NULL)
|
|
{
|
|
mz_zip_set_version_madeby(writer->zip_handle, MZ_VERSION_MADEBY);
|
|
err = mz_zip_close(writer->zip_handle);
|
|
mz_zip_delete(&writer->zip_handle);
|
|
}
|
|
|
|
if (writer->split_stream != NULL)
|
|
{
|
|
mz_stream_split_close(writer->split_stream);
|
|
mz_stream_split_delete(&writer->split_stream);
|
|
}
|
|
|
|
if (writer->buffered_stream != NULL)
|
|
mz_stream_buffered_delete(&writer->buffered_stream);
|
|
|
|
if (writer->file_stream != NULL)
|
|
mz_stream_os_delete(&writer->file_stream);
|
|
|
|
if (writer->mem_stream != NULL)
|
|
{
|
|
mz_stream_mem_close(writer->mem_stream);
|
|
mz_stream_mem_delete(&writer->mem_stream);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_writer_zip_cd(void *handle, uint16_t compress_method, int32_t flags)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
mz_zip_file cd_file;
|
|
uint64_t number_entry = 0;
|
|
int64_t cd_mem_length = 0;
|
|
int32_t err = MZ_OK;
|
|
int32_t extrafield_size = 0;
|
|
void *file_extra_stream = NULL;
|
|
void *cd_mem_stream = NULL;
|
|
|
|
|
|
memset(&cd_file, 0, sizeof(cd_file));
|
|
|
|
mz_zip_get_number_entry(writer->zip_handle, &number_entry);
|
|
mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream);
|
|
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END);
|
|
cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream);
|
|
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
|
|
|
|
cd_file.filename = MZ_ZIP_CD_FILENAME;
|
|
cd_file.modified_date = time(NULL);
|
|
cd_file.version_madeby = MZ_VERSION_MADEBY;
|
|
cd_file.compression_method = compress_method;
|
|
cd_file.uncompressed_size = (int32_t)cd_mem_length;
|
|
cd_file.flag = MZ_ZIP_FLAG_UTF8 | flags;
|
|
|
|
mz_stream_mem_create(&file_extra_stream);
|
|
mz_stream_mem_open(file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
|
|
mz_zip_extrafield_write(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, 8);
|
|
|
|
mz_stream_write_uint64(file_extra_stream, number_entry);
|
|
|
|
mz_stream_mem_get_buffer(file_extra_stream, (const void **)&cd_file.extrafield);
|
|
mz_stream_mem_get_buffer_length(file_extra_stream, &extrafield_size);
|
|
cd_file.extrafield_size = (uint16_t)extrafield_size;
|
|
|
|
err = mz_zip_writer_entry_open(handle, &cd_file);
|
|
if (err == MZ_OK)
|
|
{
|
|
mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream, NULL, (int32_t)cd_mem_length);
|
|
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
|
|
mz_stream_mem_set_buffer_limit(cd_mem_stream, 0);
|
|
|
|
err = mz_zip_entry_close(writer->zip_handle);
|
|
}
|
|
|
|
mz_stream_mem_delete(&file_extra_stream);
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
const char *password = NULL;
|
|
char password_buf[120];
|
|
|
|
// Copy file info to access data upon close
|
|
memcpy(&writer->file_info, file_info, sizeof(mz_zip_file));
|
|
|
|
if (writer->entry_cb != NULL)
|
|
writer->entry_cb(handle, writer->entry_userdata, &writer->file_info);
|
|
|
|
password = writer->password;
|
|
|
|
// Check if we need a password and ask for it if we need to
|
|
if ((writer->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
|
|
(writer->password_cb != NULL))
|
|
{
|
|
writer->password_cb(handle, writer->password_userdata, &writer->file_info,
|
|
password_buf, sizeof(password_buf));
|
|
password = password_buf;
|
|
}
|
|
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
// Start calculating sha256
|
|
mz_crypt_sha_create(&writer->sha256);
|
|
mz_crypt_sha_set_algorithm(writer->sha256, MZ_HASH_SHA256);
|
|
mz_crypt_sha_begin(writer->sha256);
|
|
#endif
|
|
|
|
// Open entry in zip
|
|
err = mz_zip_entry_write_open(writer->zip_handle, &writer->file_info, writer->compress_level,
|
|
writer->raw, password);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_entry_close(void *handle)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
const uint8_t *extrafield = NULL;
|
|
int32_t extrafield_size = 0;
|
|
int32_t field_length_hash = 0;
|
|
uint8_t sha256[MZ_HASH_SHA256_SIZE];
|
|
|
|
|
|
mz_crypt_sha_end(writer->sha256, sha256, sizeof(sha256));
|
|
mz_crypt_sha_delete(&writer->sha256);
|
|
// Copy extrafield so we can append our own fields before close
|
|
mz_stream_mem_create(&writer->file_extra_stream);
|
|
mz_stream_mem_open(writer->file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
|
|
|
|
if ((writer->file_info.extrafield != NULL) && (writer->file_info.extrafield_size > 0))
|
|
mz_stream_mem_write(writer->file_extra_stream, writer->file_info.extrafield,
|
|
writer->file_info.extrafield_size);
|
|
|
|
// Write sha256 hash to extrafield
|
|
field_length_hash = 4 + MZ_HASH_SHA256_SIZE;
|
|
err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_HASH, field_length_hash);
|
|
if (err == MZ_OK)
|
|
err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256);
|
|
if (err == MZ_OK)
|
|
err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256_SIZE);
|
|
if (err == MZ_OK)
|
|
{
|
|
if (mz_stream_write(writer->file_extra_stream, sha256, sizeof(sha256)) != MZ_HASH_SHA256_SIZE)
|
|
err = MZ_STREAM_ERROR;
|
|
}
|
|
|
|
#ifndef MZ_ZIP_NO_SIGNING
|
|
if (writer->cert_path != NULL)
|
|
err = mz_zip_writer_entry_sign(handle, sha256, sizeof(sha256), writer->cert_path, writer->cert_pwd);
|
|
#endif
|
|
|
|
// Update extra field for central directory after adding extra fields
|
|
mz_stream_mem_get_buffer(writer->file_extra_stream, (const void **)&extrafield);
|
|
mz_stream_mem_get_buffer_length(writer->file_extra_stream, &extrafield_size);
|
|
|
|
mz_zip_entry_set_extrafield(writer->zip_handle, extrafield, (uint16_t)extrafield_size);
|
|
#endif
|
|
|
|
if (writer->raw)
|
|
err = mz_zip_entry_close_raw(writer->zip_handle, writer->file_info.uncompressed_size,
|
|
writer->file_info.crc);
|
|
else
|
|
err = mz_zip_entry_close(writer->zip_handle);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t written = 0;
|
|
written = mz_zip_entry_write(writer->zip_handle, buf, len);
|
|
#ifndef MZ_ZIP_NO_ENCRYPTION
|
|
if (written > 0)
|
|
mz_crypt_sha_update(writer->sha256, buf, written);
|
|
#endif
|
|
return written;
|
|
}
|
|
|
|
#if !defined(MZ_ZIP_NO_ENCRYPTION) && !defined(MZ_ZIP_NO_SIGNING)
|
|
int32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size,
|
|
const char *cert_path, const char *cert_pwd)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
int32_t signature_size = 0;
|
|
uint8_t *signature = NULL;
|
|
|
|
|
|
if (writer == NULL || mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (cert_path == NULL)
|
|
{
|
|
cert_path = writer->cert_path;
|
|
cert_pwd = writer->cert_pwd;
|
|
}
|
|
if (cert_path == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
if (err == MZ_OK)
|
|
{
|
|
err = mz_crypt_sign(message, message_size, cert_path, cert_pwd, &signature, &signature_size);
|
|
}
|
|
|
|
if ((err == MZ_OK) && (signature != NULL))
|
|
{
|
|
// Write signature zip extra field
|
|
err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_SIGN, signature_size);
|
|
if (err == MZ_OK)
|
|
{
|
|
if (mz_stream_write(writer->file_extra_stream, signature, signature_size) != signature_size)
|
|
err = MZ_STREAM_ERROR;
|
|
}
|
|
|
|
MZ_FREE(signature);
|
|
}
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************/
|
|
|
|
int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t read = 0;
|
|
int32_t written = 0;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_writer_is_open(writer) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
// If the entry isn't open for writing, open it
|
|
if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (read_cb == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
read = read_cb(stream, writer->buffer, sizeof(writer->buffer));
|
|
if (read == 0)
|
|
return MZ_END_OF_STREAM;
|
|
if (read < 0)
|
|
{
|
|
err = read;
|
|
return err;
|
|
}
|
|
|
|
written = mz_zip_writer_entry_write(handle, writer->buffer, read);
|
|
if (written != read)
|
|
return MZ_STREAM_ERROR;
|
|
|
|
return written;
|
|
}
|
|
|
|
int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
uint64_t current_time = 0;
|
|
uint64_t update_time = 0;
|
|
int64_t current_pos = 0;
|
|
int64_t update_pos = 0;
|
|
int32_t err = MZ_OK;
|
|
int32_t written = 0;
|
|
|
|
// Update the progress at the beginning
|
|
if (writer->progress_cb != NULL)
|
|
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
|
|
|
|
// Write data to stream until done
|
|
while (err == MZ_OK)
|
|
{
|
|
written = mz_zip_writer_add_process(handle, stream, read_cb);
|
|
if (written == MZ_END_OF_STREAM)
|
|
break;
|
|
if (written > 0)
|
|
current_pos += written;
|
|
if (written < 0)
|
|
err = written;
|
|
|
|
// Update progress if enough time have passed
|
|
current_time = mz_os_ms_time();
|
|
if ((current_time - update_time) > writer->progress_cb_interval_ms)
|
|
{
|
|
if (writer->progress_cb != NULL)
|
|
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
|
|
|
|
update_pos = current_pos;
|
|
update_time = current_time;
|
|
}
|
|
}
|
|
|
|
// Update the progress at the end
|
|
if (writer->progress_cb != NULL && update_pos != current_pos)
|
|
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
if (mz_zip_writer_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (file_info == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// Add to zip
|
|
err = mz_zip_writer_entry_open(handle, file_info);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
if (stream != NULL)
|
|
{
|
|
if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK)
|
|
{
|
|
err = mz_zip_writer_add(handle, stream, read_cb);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
}
|
|
}
|
|
|
|
err = mz_zip_writer_entry_close(handle);
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info)
|
|
{
|
|
void *mem_stream = NULL;
|
|
int32_t err = MZ_OK;
|
|
|
|
if (mz_zip_writer_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (buf == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
// Create a memory stream backed by our buffer and add from it
|
|
mz_stream_mem_create(&mem_stream);
|
|
mz_stream_mem_set_buffer(mem_stream, buf, len);
|
|
|
|
err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
|
|
if (err == MZ_OK)
|
|
err = mz_zip_writer_add_info(handle, mem_stream, mz_stream_mem_read, file_info);
|
|
|
|
mz_stream_mem_delete(&mem_stream);
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
mz_zip_file file_info;
|
|
uint32_t target_attrib = 0;
|
|
uint32_t src_attrib = 0;
|
|
int32_t err = MZ_OK;
|
|
uint8_t src_sys = 0;
|
|
void *stream = NULL;
|
|
const char *filename = filename_in_zip;
|
|
|
|
|
|
if (mz_zip_writer_is_open(handle) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (path == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
if (filename == NULL)
|
|
{
|
|
err = mz_path_get_filename(path, &filename);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
}
|
|
|
|
memset(&file_info, 0, sizeof(file_info));
|
|
|
|
// The path name saved, should not include a leading slash.
|
|
// If it did, windows/xp and dynazip couldn't read the zip file.
|
|
|
|
while (filename[0] == '\\' || filename[0] == '/')
|
|
filename += 1;
|
|
|
|
// Get information about the file on disk so we can store it in zip
|
|
|
|
file_info.version_madeby = MZ_VERSION_MADEBY;
|
|
file_info.compression_method = writer->compress_method;
|
|
file_info.filename = filename;
|
|
file_info.uncompressed_size = mz_os_get_file_size(path);
|
|
file_info.flag = MZ_ZIP_FLAG_UTF8 | writer->flags;
|
|
|
|
#ifdef HAVE_AES
|
|
if (writer->aes)
|
|
file_info.aes_version = MZ_AES_VERSION;
|
|
#endif
|
|
|
|
mz_os_get_file_date(path, &file_info.modified_date, &file_info.accessed_date,
|
|
&file_info.creation_date);
|
|
mz_os_get_file_attribs(path, &src_attrib);
|
|
|
|
src_sys = MZ_HOST_SYSTEM(file_info.version_madeby);
|
|
|
|
if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS))
|
|
{
|
|
// High bytes are OS specific attributes, low byte is always DOS attributes
|
|
if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK)
|
|
file_info.external_fa = target_attrib;
|
|
file_info.external_fa |= (src_attrib << 16);
|
|
}
|
|
else
|
|
{
|
|
file_info.external_fa = src_attrib;
|
|
}
|
|
|
|
if (mz_os_is_dir(path) != MZ_OK)
|
|
{
|
|
mz_stream_os_create(&stream);
|
|
err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
|
|
}
|
|
|
|
if (err == MZ_OK)
|
|
err = mz_zip_writer_add_info(handle, stream, mz_stream_os_read, &file_info);
|
|
|
|
if (stream != NULL)
|
|
{
|
|
mz_stream_os_close(stream);
|
|
mz_stream_os_delete(&stream);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path,
|
|
uint8_t recursive)
|
|
{
|
|
DIR *dir = NULL;
|
|
struct dirent *entry = NULL;
|
|
int32_t err = MZ_OK;
|
|
int16_t is_dir = 0;
|
|
const char *filename = NULL;
|
|
const char *filenameinzip = path;
|
|
char *wildcard_ptr = NULL;
|
|
char full_path[320];
|
|
char path_dir[320];
|
|
|
|
|
|
if (mz_os_is_dir(path) == MZ_OK)
|
|
is_dir = 1;
|
|
|
|
if (strrchr(path, '*') != NULL)
|
|
{
|
|
strncpy(path_dir, path, sizeof(path_dir) - 1);
|
|
path_dir[sizeof(path_dir) - 1] = 0;
|
|
mz_path_remove_filename(path_dir);
|
|
wildcard_ptr = path_dir + strlen(path_dir) + 1;
|
|
root_path = path = path_dir;
|
|
}
|
|
else
|
|
{
|
|
// Construct the filename that our file will be stored in the zip as
|
|
if (root_path == NULL)
|
|
root_path = path;
|
|
|
|
// Should the file be stored with any path info at all?
|
|
if (!include_path)
|
|
{
|
|
if (!is_dir && root_path == path)
|
|
{
|
|
if (mz_path_get_filename(filenameinzip, &filename) == MZ_OK)
|
|
filenameinzip = filename;
|
|
}
|
|
else
|
|
{
|
|
filenameinzip += strlen(root_path);
|
|
}
|
|
}
|
|
|
|
if (*filenameinzip != 0)
|
|
err = mz_zip_writer_add_file(handle, path, filenameinzip);
|
|
|
|
if (!is_dir)
|
|
return err;
|
|
}
|
|
|
|
dir = mz_os_open_dir(path);
|
|
|
|
if (dir == NULL)
|
|
return MZ_EXIST_ERROR;
|
|
|
|
while ((entry = mz_os_read_dir(dir)) != NULL)
|
|
{
|
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
|
continue;
|
|
|
|
full_path[0] = 0;
|
|
mz_path_combine(full_path, path, sizeof(full_path));
|
|
mz_path_combine(full_path, entry->d_name, sizeof(full_path));
|
|
|
|
if (!recursive && mz_os_is_dir(full_path))
|
|
continue;
|
|
if ((wildcard_ptr != NULL) && (mz_path_compare_wc(entry->d_name, wildcard_ptr, 1) != MZ_OK))
|
|
continue;
|
|
|
|
err = mz_zip_writer_add_path(handle, full_path, root_path, include_path, recursive);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
}
|
|
|
|
mz_os_close_dir(dir);
|
|
return MZ_OK;
|
|
}
|
|
|
|
int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
mz_zip_file *file_info = NULL;
|
|
int32_t err = MZ_OK;
|
|
uint8_t original_raw = 0;
|
|
void *reader_zip_handle = NULL;
|
|
|
|
|
|
if (mz_zip_reader_is_open(reader) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
if (mz_zip_writer_is_open(writer) != MZ_OK)
|
|
return MZ_PARAM_ERROR;
|
|
|
|
err = mz_zip_reader_entry_get_info(reader, &file_info);
|
|
if (err != MZ_OK)
|
|
return err;
|
|
|
|
mz_zip_reader_get_zip_handle(reader, &reader_zip_handle);
|
|
|
|
// Open entry for raw reading
|
|
err = mz_zip_entry_read_open(reader_zip_handle, 1, NULL);
|
|
if (err == MZ_OK)
|
|
{
|
|
// Write entry raw, save original raw value
|
|
original_raw = writer->raw;
|
|
writer->raw = 1;
|
|
|
|
err = mz_zip_writer_add_info(writer, reader_zip_handle, mz_zip_entry_read, file_info);
|
|
|
|
writer->raw = original_raw;
|
|
|
|
mz_zip_entry_close(reader_zip_handle);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void mz_zip_writer_set_password(void *handle, const char *password)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->password = password;
|
|
}
|
|
|
|
void mz_zip_writer_set_raw(void *handle, uint8_t raw)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->raw = raw;
|
|
}
|
|
|
|
int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
if (raw == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
*raw = writer->raw;
|
|
return MZ_OK;
|
|
}
|
|
|
|
void mz_zip_writer_set_aes(void *handle, uint8_t aes)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->aes = aes;
|
|
}
|
|
|
|
void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->compress_method = compress_method;
|
|
}
|
|
|
|
void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->compress_level = compress_level;
|
|
}
|
|
|
|
void mz_zip_writer_set_flags(void *handle, int32_t flags)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->flags = flags;
|
|
}
|
|
|
|
void mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->cert_path = cert_path;
|
|
writer->cert_pwd = cert_pwd;
|
|
}
|
|
|
|
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->overwrite_cb = cb;
|
|
writer->overwrite_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->password_cb = cb;
|
|
writer->password_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->progress_cb = cb;
|
|
writer->progress_userdata = userdata;
|
|
}
|
|
|
|
void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->progress_cb_interval_ms = milliseconds;
|
|
}
|
|
|
|
void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
writer->entry_cb = cb;
|
|
writer->entry_userdata = userdata;
|
|
}
|
|
|
|
int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle)
|
|
{
|
|
mz_zip_writer *writer = (mz_zip_writer *)handle;
|
|
if (zip_handle == NULL)
|
|
return MZ_PARAM_ERROR;
|
|
*zip_handle = writer->zip_handle;
|
|
if (*zip_handle == NULL)
|
|
return MZ_EXIST_ERROR;
|
|
return MZ_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void *mz_zip_writer_create(void **handle)
|
|
{
|
|
mz_zip_writer *writer = NULL;
|
|
|
|
writer = (mz_zip_writer *)MZ_ALLOC(sizeof(mz_zip_writer));
|
|
if (writer != NULL)
|
|
{
|
|
memset(writer, 0, sizeof(mz_zip_writer));
|
|
|
|
writer->aes = 1;
|
|
writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE;
|
|
writer->compress_level = MZ_COMPRESS_LEVEL_BEST;
|
|
writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
|
|
|
|
*handle = writer;
|
|
}
|
|
|
|
return writer;
|
|
}
|
|
|
|
void mz_zip_writer_delete(void **handle)
|
|
{
|
|
mz_zip_writer *writer = NULL;
|
|
if (handle == NULL)
|
|
return;
|
|
writer = (mz_zip_writer *)*handle;
|
|
if (writer != NULL)
|
|
{
|
|
mz_zip_writer_close(writer);
|
|
MZ_FREE(writer);
|
|
}
|
|
*handle = NULL;
|
|
}
|
|
|
|
/***************************************************************************/
|