gmio_core/internal: add ZIP utils

This commit is contained in:
Hugues Delorme 2016-12-23 13:04:52 +01:00
parent d8da7293ef
commit 73eb7a522e
2 changed files with 645 additions and 0 deletions

View File

@ -0,0 +1,361 @@
/****************************************************************************
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above
** copyright notice, this list of conditions and the following
** disclaimer in the documentation and/or other materials provided
** with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#include "zip_utils.h"
#include "../error.h"
#include "byte_codec.h"
#include "helper_stream.h"
#include <stddef.h>
/* ----------
* Constants
* ---------- */
enum {
GMIO_ZIP_SIZE_LOCAL_FILE_HEADER = 4 + 5*2 + 3*4 + 2*2,
GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER = 4 + 6*2 + 3*4 + 5*2 +2*4,
GMIO_ZIP64_SIZE_DATA_DESCRIPTOR = 4 + 2*8,
GMIO_ZIP_SIZE_DATA_DESCRIPTOR = 4 + 2*4,
GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 4*2 + 2*4 + 2
};
/* ----------
* Internal functions
* ---------- */
/* See http://www.vsft.com/hal/dostime.htm */
static uint32_t gmio_to_msdos_datetime(const struct tm* datetime)
{
const uint32_t msdos_datetime =
/* Time */
(datetime->tm_sec) /* bit 0-4 */
| (datetime->tm_min << 5) /* bit 5-10 */
| (datetime->tm_hour << 11) /* bit 11-15 */
/* Date */
| (datetime->tm_mday << 16) /* bit 16-20 */
| ((datetime->tm_mon + 1) << 21) /* bit 21-24 */
| ((datetime->tm_year - 80) << 25); /* bit 21-24 */
return msdos_datetime;
}
/* Returns a non-null datetime, if arg is NULL it returns current gmtime() */
static const struct tm* gmio_nonnull_datetime(const struct tm* datetime)
{
if (datetime == NULL) {
const time_t current_time = time(NULL);
return gmtime(&current_time); /* UTC time */
}
return datetime;
}
#ifdef GMIO_HAVE_INT64_TYPE
/* Encodes little-endian 64b val in buffer and returns advanced buffer pos */
static uint8_t* gmio_adv_encode_uint64_le(uint64_t val, uint8_t* bytes)
{
gmio_encode_uint64_le(val, bytes);
return bytes + 8;
}
#endif
/* Encodes little-endian 32b val in buffer and returns advanced buffer pos */
static uint8_t* gmio_adv_encode_uint32_le(uint32_t val, uint8_t* bytes)
{
gmio_encode_uint32_le(val, bytes);
return bytes + 4;
}
/* Encodes little-endian 16b val in buffer and returns advanced buffer pos */
static uint8_t* gmio_adv_encode_uint16_le(uint16_t val, uint8_t* bytes)
{
gmio_encode_uint16_le(val, bytes);
return bytes + 2;
}
/* Helper to facilitate return from gmio_zip_write_xxx() API functions */
static size_t gmio_zip_write_returnhelper(
struct gmio_stream* stream, size_t written, size_t expected, int* error)
{
if (error != NULL) {
const bool no_error = written == expected && !gmio_stream_error(stream);
*error = no_error ? GMIO_ERROR_OK : GMIO_ERROR_STREAM;
}
return written;
}
/* ----------
* API functions
* ---------- */
size_t gmio_zip_write_local_file_header(
struct gmio_stream* stream,
const struct gmio_zip_local_file_header* info,
int* error)
{
uint8_t fixed_data[GMIO_ZIP_SIZE_LOCAL_FILE_HEADER];
uint8_t* buff = fixed_data;
const bool use_data_descriptor =
info->general_purpose_flags & GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR;
/* 4-bytes magic number 0x04034b50 */
buff = gmio_adv_encode_uint32_le(0x04034b50, buff);
/* 2-bytes version needed to extract */
buff = gmio_adv_encode_uint16_le(info->version_needed_to_extract, buff);
/* 2-bytes general purpose bit flag */
buff = gmio_adv_encode_uint16_le(info->general_purpose_flags, buff);
/* 2-bytes compression method */
buff = gmio_adv_encode_uint16_le(info->compress_method, buff);
/* 2-bytes last mod file time */
/* 2-bytes last mod file date */
const struct tm* lastmod = gmio_nonnull_datetime(info->lastmod_datetime);
buff = gmio_adv_encode_uint32_le(gmio_to_msdos_datetime(lastmod), buff);
/* 4-bytes crc-32 */
buff = gmio_adv_encode_uint32_le(
use_data_descriptor ? 0 : info->crc32, buff);
/* 4-bytes compressed size */
buff = gmio_adv_encode_uint32_le(
use_data_descriptor ? 0 : info->compressed_size, buff);
/* 4-bytes uncompressed size */
buff = gmio_adv_encode_uint32_le(
use_data_descriptor ? 0 : info->uncompressed_size, buff);
/* 2-bytes file name length */
buff = gmio_adv_encode_uint16_le(info->filename_len, buff);
/* 2-bytes extra field length */
buff = gmio_adv_encode_uint16_le(info->extrafield_len, buff);
/* Write to stream */
const size_t expected_written_len =
sizeof(fixed_data) + info->filename_len + info->extrafield_len;
size_t written_len = 0;
written_len +=
gmio_stream_write_bytes(stream, fixed_data, sizeof(fixed_data));
written_len +=
gmio_stream_write_bytes(stream, info->filename, info->filename_len);
written_len +=
gmio_stream_write_bytes(stream, info->extrafield, info->extrafield_len);
return gmio_zip_write_returnhelper(
stream, written_len, expected_written_len, error);
}
size_t gmio_zip_write_data_descriptor(
struct gmio_stream *stream,
const struct gmio_zip_data_descriptor *info,
int* error)
{
const size_t fixed_data_len =
info->use_zip64 ?
GMIO_ZIP64_SIZE_DATA_DESCRIPTOR :
GMIO_ZIP_SIZE_DATA_DESCRIPTOR;
uint8_t fixed_data[GMIO_ZIP64_SIZE_DATA_DESCRIPTOR];
uint8_t* buff = fixed_data;
/* 4-bytes crc-32 */
buff = gmio_adv_encode_uint32_le(info->crc32, buff);
/* Compressed size and uncompressed size (4 or 8 bytes) */
if (info->use_zip64) {
#ifdef GMIO_HAVE_INT64_TYPE
buff = gmio_adv_encode_uint64_le(info->compressed_size, buff);
buff = gmio_adv_encode_uint64_le(info->uncompressed_size, buff);
#else
return GMIO_ERROR_UNKNOWN; /* TODO: error code */
#endif
}
else {
if (info->compressed_size <= UINT32_MAX
&& info->uncompressed_size <= UINT32_MAX)
{
buff = gmio_adv_encode_uint32_le((uint32_t)info->compressed_size, buff);
buff = gmio_adv_encode_uint32_le((uint32_t)info->uncompressed_size, buff);
}
else {
return GMIO_ERROR_UNKNOWN; /* TODO: error code */
}
}
/* Write to stream */
const size_t written_len =
gmio_stream_write_bytes(stream, fixed_data, fixed_data_len);
return gmio_zip_write_returnhelper(
stream, written_len, fixed_data_len, error);
}
size_t gmio_zip_write_central_directory_header(
struct gmio_stream *stream,
const struct gmio_zip_central_directory_header *info,
int* error)
{
uint8_t fixed_data[GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER];
uint8_t* buff = fixed_data;
/* 4-bytes magic number 0x02014b50 */
buff = gmio_adv_encode_uint32_le(0x02014b50, buff);
/* 2-bytes version made by */
buff = gmio_adv_encode_uint16_le(info->version_made_by, buff);
/* 2-bytes version needed to extract */
buff = gmio_adv_encode_uint16_le(info->version_needed_to_extract, buff);
/* 2-bytes general purpose bit flag */
buff = gmio_adv_encode_uint16_le(info->general_purpose_flags, buff);
/* 2-bytes compression method */
buff = gmio_adv_encode_uint16_le(info->compress_method, buff);
/* 2-bytes last mod file time */
/* 2-bytes last mod file date */
const struct tm* lastmod = gmio_nonnull_datetime(info->lastmod_datetime);
buff = gmio_adv_encode_uint32_le(gmio_to_msdos_datetime(lastmod), buff);
/* 4-bytes crc-32 */
buff = gmio_adv_encode_uint32_le(info->crc32, buff);
/* 4-bytes compressed size */
const uint32_t compressed_size =
info->use_zip64 ? UINT32_MAX : info->compressed_size;
buff = gmio_adv_encode_uint32_le(compressed_size, buff);
/* 4-bytes uncompressed size */
const uint32_t uncompressed_size =
info->use_zip64 ? UINT32_MAX : info->uncompressed_size;
buff = gmio_adv_encode_uint32_le(uncompressed_size, buff);
/* 2-bytes file name length */
buff = gmio_adv_encode_uint16_le(info->filename_len, buff);
/* 2-bytes extra field length */
buff = gmio_adv_encode_uint16_le(info->extrafield_len, buff);
/* 2-bytes file comment length */
buff = gmio_adv_encode_uint16_le(info->filecomment_len, buff);
/* 2-bytes disk number start */
buff = gmio_adv_encode_uint16_le(info->disk_nb_start, buff);
/* 2-bytes internal file attributes */
buff = gmio_adv_encode_uint16_le(info->internal_file_attrs, buff);
/* 4-bytes external file attributes */
buff = gmio_adv_encode_uint32_le(info->external_file_attrs, buff);
/* 4-bytes relative offset of local header */
const uint32_t relative_offset_local_header =
info->use_zip64 ? UINT32_MAX : info->relative_offset_local_header;
buff = gmio_adv_encode_uint32_le(relative_offset_local_header, buff);
/* Write to stream */
const size_t expected_written_len =
sizeof(fixed_data)
+ info->filename_len + info->extrafield_len + info->filecomment_len;
size_t written_len = 0;
written_len +=
gmio_stream_write_bytes(stream, fixed_data, sizeof(fixed_data));
written_len +=
gmio_stream_write_bytes(stream, info->filename, info->filename_len);
written_len +=
gmio_stream_write_bytes(stream, info->extrafield, info->extrafield_len);
written_len +=
gmio_stream_write_bytes(stream, info->filecomment, info->filecomment_len);
return gmio_zip_write_returnhelper(
stream, written_len, expected_written_len, error);
}
size_t gmio_zip64_write_extrafield_extended_info(
uint8_t *buff,
size_t buff_capacity,
const struct gmio_zip64_extrablock_extended_info *info,
int* error)
{
if (buff_capacity < GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO) {
*error = GMIO_ERROR_INVALID_MEMBLOCK_SIZE;
return 0;
}
#ifdef GMIO_HAVE_INT64_TYPE
/* Tag */
buff = gmio_adv_encode_uint16_le(0x0001, buff);
/* Size of the "extra" block */
buff = gmio_adv_encode_uint16_le(
GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO - 2, buff);
/* Original uncompressed file size */
buff = gmio_adv_encode_uint64_le(info->uncompressed_size, buff);
/* Size of compressed data */
buff = gmio_adv_encode_uint64_le(info->compressed_size, buff);
/* Offset of local header record */
buff = gmio_adv_encode_uint64_le(info->relative_offset_local_header, buff);
/* Number of the disk on which this file starts */
buff = gmio_adv_encode_uint32_le(info->disk_nb_start, buff);
*error = GMIO_ERROR_OK;
return GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO;
#else
*error = GMIO_ERROR_UNKNOWN; /* TODO: error code */
return 0;
#endif
}
size_t gmio_zip_write_end_of_central_directory_record(
struct gmio_stream *stream,
const struct gmio_zip_end_of_central_directory_record *info,
int* error)
{
uint8_t fixed_data[GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD];
uint8_t* buff = fixed_data;
/* 4-bytes magic number 0x06054b50 */
buff = gmio_adv_encode_uint32_le(0x06054b50, buff);
/* 2-bytes number of this disk */
const uint16_t disk_nb = info->use_zip64 ? UINT16_MAX : info->disk_nb;
buff = gmio_adv_encode_uint16_le(disk_nb, buff);
/* 2-bytes number of the disk with the start of the central directory */
const uint16_t disk_nb_with_start_of_central_dir =
info->use_zip64 ? UINT16_MAX : info->disk_nb_with_start_of_central_dir;
buff = gmio_adv_encode_uint16_le(disk_nb_with_start_of_central_dir, buff);
/* 2-bytes total number of entries in the central directory on this disk */
const uint16_t total_entry_count_in_central_dir_on_disk =
info->use_zip64 ? UINT16_MAX : info->total_entry_count_in_central_dir_on_disk;
buff = gmio_adv_encode_uint16_le(total_entry_count_in_central_dir_on_disk, buff);
/* 2-bytes total number of entries in the central directory */
const uint16_t total_entry_count_in_central_dir =
info->use_zip64 ? UINT16_MAX : info->total_entry_count_in_central_dir;
buff = gmio_adv_encode_uint16_le(total_entry_count_in_central_dir, buff);
/* 4-bytes size of the central directory */
const uint32_t central_dir_size =
info->use_zip64 ? UINT32_MAX : info->central_dir_size;
buff = gmio_adv_encode_uint32_le(central_dir_size, buff);
/* 4-bytes offset of start of central directory with respect to the starting
* disk number */
const uint32_t start_offset_central_dir_from_disk_start_nb =
info->use_zip64 ? UINT32_MAX : info->start_offset_central_dir_from_disk_start_nb;
buff = gmio_adv_encode_uint32_le(start_offset_central_dir_from_disk_start_nb, buff);
/* 2-bytes .ZIP file comment length */
buff = gmio_adv_encode_uint16_le(info->filecomment_len, buff);
/* Write to stream */
const size_t expected_written_len =
sizeof(fixed_data) + info->filecomment_len;
size_t written_len = 0;
written_len +=
gmio_stream_write_bytes(stream, fixed_data, sizeof(fixed_data));
written_len +=
gmio_stream_write_bytes(stream, info->filecomment, info->filecomment_len);
return gmio_zip_write_returnhelper(
stream, written_len, expected_written_len, error);
}

View File

@ -0,0 +1,284 @@
/****************************************************************************
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above
** copyright notice, this list of conditions and the following
** disclaimer in the documentation and/or other materials provided
** with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#ifndef GMIO_INTERNAL_ZIP_UTILS_H
#define GMIO_INTERNAL_ZIP_UTILS_H
#include "../global.h"
#include "../stream.h"
#include <time.h>
enum gmio_zip_compress_method {
GMIO_ZIP_COMPRESS_METHOD_NO_COMPRESSION = 0,
GMIO_ZIP_COMPRESS_METHOD_SHRUNK = 1,
GMIO_ZIP_COMPRESS_METHOD_REDUCE_FACTOR_1 = 2,
GMIO_ZIP_COMPRESS_METHOD_REDUCE_FACTOR_2 = 3,
GMIO_ZIP_COMPRESS_METHOD_REDUCE_FACTOR_3 = 4,
GMIO_ZIP_COMPRESS_METHOD_REDUCE_FACTOR_4 = 5,
GMIO_ZIP_COMPRESS_METHOD_IMPLODE = 6,
GMIO_ZIP_COMPRESS_METHOD_DEFLATE = 8,
GMIO_ZIP_COMPRESS_METHOD_DEFLATE64 = 9,
GMIO_ZIP_COMPRESS_METHOD_PKWARE_IMPLODE = 10,
GMIO_ZIP_COMPRESS_METHOD_BZIP2 = 12,
GMIO_ZIP_COMPRESS_METHOD_LZMA = 14,
GMIO_ZIP_COMPRESS_METHOD_IBM_TERSE = 18,
GMIO_ZIP_COMPRESS_METHOD_IBM_LZ77 = 19,
GMIO_ZIP_COMPRESS_METHOD_WAVPACK = 97,
GMIO_ZIP_COMPRESS_METHOD_PPMD_VERSION_I_REV_1 = 98
};
enum gmio_zip_general_purpose_flag {
/*! Bit_0: if set, indicates that the file is encrypted */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_FILE_ENCRYPTED = 0x0001,
/* For Method 6 - Imploding */
/*! Bit_1: if set, indicates an 8K sliding dictionary was used. If clear,
* then a 4K sliding dictionary was used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_IMPLODE_8K_SLIDING_DICT = 0x0002,
/*! Bit_2: if set, indicates 3 Shannon-Fano trees were used to encode the
* sliding dictionary output. If clear, then 2 Shannon-Fano trees
* were used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_IMPLODE_3_SHANNON_FANO_TREES = 0x0004,
/* For Methods 8 and 9 - Deflating */
/*! Bit_2=0 Bit_1=0 -> Normal (-en) compression option was used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_DEFLATE_COMPRESS_NORMAL = 0x0000,
/*! Bit_2=0 Bit_1=1 -> Maximum (-exx/-ex) compression option was used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_DEFLATE_COMPRESS_MAX = 0x0002,
/*! Bit_2=1 Bit_1=0 -> Fast (-ef) compression option was used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_DEFLATE_COMPRESS_FAST = 0x0004,
/*! Bit_2=1 Bit_1=1 -> Super Fast (-es) compression option was used */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_DEFLATE_COMPRESS_SUPER_FAST = 0x0006,
/* For Method 14 - LZMA */
/*! Bit_1: if set, indicates an end-of-stream (EOS) marker is used to mark
* the end of the compressed data stream. If clear, then an EOS
* marker is not present and the compressed data size must be known
* to extract */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_LZMA_USE_EOS_MARKER = 0x0002,
/*! Bit_3: if set, the fields crc-32, compressed size and uncompressed size
* are set to zero in the local header.
* The correct values are put in the data descriptor immediately
* following the compressed data */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR = 0x0008,
/*! Bit_5: if set, indicates that the file is compressed patched data.
* (Note: Requires PKZIP version 2.70 or greater) */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_COMPRESSED_PATCHED_DATA = 0x0020,
/*! Bit_6: Strong encryption. If set, you MUST set the version needed to
* extract value to at least 50 and you MUST also set bit 0. If AES
* encryption is used, the version needed to extract value MUST be
* at least 51. */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_STRONG_ENCRYPTION = 0x0040,
/*! Bit_11: Language encoding flag (EFS). If set, the filename and comment
* fields for this file MUST be encoded using UTF-8 */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_ENCODING_UTF8 = 0x0800,
/*! Bit_13: Set when encrypting the Central Directory to indicate selected
* data values in the Local Header are masked to hide their actual
* values */
GMIO_ZIP_GENERAL_PURPOSE_FLAG_MASK_LOCAL_HEADER = 0x2000
};
/*! Header ID mapping defined by PKWARE */
enum gmio_zip_pkware_headerid
{
GMIO_ZIP_PKWARE_HEADERID_ZIP64_EXTENDED_INFO = 0x0001,
GMIO_ZIP_PKWARE_HEADERID_AV_INFO = 0x0007,
GMIO_ZIP_PKWARE_HEADERID_EXTENDED_LANGUAGE_ENCODE_DATA = 0x0008,
GMIO_ZIP_PKWARE_HEADERID_OS2 = 0x0009,
GMIO_ZIP_PKWARE_HEADERID_NTFS = 0x000A,
GMIO_ZIP_PKWARE_HEADERID_OPENVMS = 0x000C,
GMIO_ZIP_PKWARE_HEADERID_UNIX = 0x000D,
GMIO_ZIP_PKWARE_HEADERID_STREAM_AND_FORK_DESCRIPTORS = 0x000E,
GMIO_ZIP_PKWARE_HEADERID_PATCH_DESCRIPTOR = 0x000F,
GMIO_ZIP_PKWARE_HEADERID_PKCS7_X509_CERT = 0x0014,
GMIO_ZIP_PKWARE_HEADERID_X509_CERTID_FOR_FILE = 0x0015,
GMIO_ZIP_PKWARE_HEADERID_X509_CERTID_FOR_CENTRAL_DIRECTORY = 0x0016,
GMIO_ZIP_PKWARE_HEADERID_STRONG_ENCRYPTION_HEADER = 0x0017,
GMIO_ZIP_PKWARE_HEADERID_RECORD_MANAGEMENT_CONTROLS = 0x0018,
GMIO_ZIP_PKWARE_HEADERID_PKCS7_ENCRYPTION_RECIPIENT_CERT_LIST = 0x0019
};
enum gmio_zip_feature_version {
GMIO_ZIP_FEATURE_VERSION_DEFAULT = 10,
GMIO_ZIP_FEATURE_VERSION_FILE_VOLUME_LABEL = 11,
GMIO_ZIP_FEATURE_VERSION_FILE_FOLDER = 20,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_DEFLATE = 20,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_PKWARE = 20,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_DEFLATE64 = 21,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_PKWARE_DCL_IMPLODE = 25,
GMIO_ZIP_FEATURE_VERSION_FILE_PATCH_DATA_SET = 27,
GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS = 45,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_BZIP2 = 46,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_DES = 50,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_3DES = 50,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_RC2 = 50,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_RC4 = 50,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_AES = 51,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_RC2_CORRECTED = 51,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_RC2_64_CORRECTED = 52,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_NON_OAEP_KEY_WRAP = 61,
GMIO_ZIP_FEATURE_VERSION_CENTRAL_DIRECTORY_ENCRYPTION = 62,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_LZMA = 63,
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_PPMD_PLUS = 63,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_BLOWFISH = 63,
GMIO_ZIP_FEATURE_VERSION_FILE_ENCRYPTED_TWOFISH = 63
};
/*! Zip local file header */
struct gmio_zip_local_file_header {
enum gmio_zip_feature_version version_needed_to_extract;
uint16_t general_purpose_flags;
enum gmio_zip_compress_method compress_method;
const struct tm* lastmod_datetime;
uint32_t crc32;
uint32_t compressed_size;
uint32_t uncompressed_size;
const char* filename;
const uint8_t* extrafield;
uint16_t filename_len;
uint16_t extrafield_len;
};
/*! Zip data descriptor */
struct gmio_zip_data_descriptor {
bool use_zip64;
uint32_t crc32;
uintmax_t compressed_size;
uintmax_t uncompressed_size;
};
/*! Zip central directory header */
struct gmio_zip_central_directory_header {
bool use_zip64;
uint16_t version_made_by;
enum gmio_zip_feature_version version_needed_to_extract;
uint16_t general_purpose_flags;
enum gmio_zip_compress_method compress_method;
const struct tm* lastmod_datetime;
uint32_t crc32;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint16_t filename_len;
uint16_t extrafield_len;
uint16_t filecomment_len;
uint16_t disk_nb_start;
uint16_t internal_file_attrs;
uint32_t external_file_attrs;
uint32_t relative_offset_local_header;
const char* filename;
const uint8_t* extrafield;
const char* filecomment;
};
enum {
GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO = 2*2 + 3*8 + 4
};
/*! Zip64 extended info (extra field) */
struct gmio_zip64_extrablock_extended_info {
uintmax_t compressed_size;
uintmax_t uncompressed_size;
uintmax_t relative_offset_local_header;
uint32_t disk_nb_start;
};
/*! Zip end of central directory record */
struct gmio_zip_end_of_central_directory_record {
bool use_zip64;
uint16_t disk_nb;
uint16_t disk_nb_with_start_of_central_dir;
uint16_t total_entry_count_in_central_dir_on_disk;
uint16_t total_entry_count_in_central_dir;
uint32_t central_dir_size;
uint32_t start_offset_central_dir_from_disk_start_nb;
uint16_t filecomment_len;
const char* filecomment;
};
/*! Zip64 end of central directory record */
struct gmio_zip64_end_of_central_directory_record {
uintmax_t remaining_record_size; /* should be 64b */
uint16_t version_made_by;
enum gmio_zip_feature_version version_needed_to_extract;
uint32_t disk_nb;
uint32_t disk_nb_with_start_of_central_dir;
uintmax_t total_entry_count_in_central_dir_on_disk; /* should be 64b */
uintmax_t total_entry_count_in_central_dir; /* should be 64b */
uintmax_t central_dir_size; /* should be 64b */
uintmax_t start_offset_central_dir_from_disk_start_nb; /* should be 64b */
const uint8_t* extensible_data_sector; /* Reserved for use by PKWARE */
};
struct gmio_zip_write_result {
int error;
size_t written_len;
};
/*! Writes ZIP local file header to \p stream */
size_t gmio_zip_write_local_file_header(
struct gmio_stream* stream,
const struct gmio_zip_local_file_header* info,
int* error);
/*! Writes ZIP data descriptor to \p stream */
size_t gmio_zip_write_data_descriptor(
struct gmio_stream* stream,
const struct gmio_zip_data_descriptor* info,
int* error);
/*! Writes ZIP central directory header to \p stream */
size_t gmio_zip_write_central_directory_header(
struct gmio_stream* stream,
const struct gmio_zip_central_directory_header* info,
int* error);
/*! Writes ZIP local file header to \p buff
*
* Returns \c GMIO_ERROR_INVALID_MEMBLOCK_SIZE if \p buff_capacity is less than
* \c GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO
*/
size_t gmio_zip64_write_extrafield_extended_info(
uint8_t* buff,
size_t buff_capacity,
const struct gmio_zip64_extrablock_extended_info* info,
int* error);
/*! Writes ZIP end of central directory record \p stream */
size_t gmio_zip_write_end_of_central_directory_record(
struct gmio_stream* stream,
const struct gmio_zip_end_of_central_directory_record* info,
int* error);
#endif /* GMIO_INTERNAL_ZIP_UTILS_H */