Merge branch 'develop' of https://github.com/fougue/gmio into develop
This commit is contained in:
commit
579989484c
@ -632,7 +632,8 @@ static size_t gmio_amf_ostringstream_write_zlib(
|
||||
int z_retcode = Z_OK;
|
||||
|
||||
context->z_uncompressed_size += len;
|
||||
context->z_crc32 = crc32(context->z_crc32, (const Bytef*)ptr, len);
|
||||
context->z_crc32 =
|
||||
gmio_zlib_crc32_update(context->z_crc32, (const uint8_t*)ptr, len);
|
||||
|
||||
z_stream->next_in = (z_const Bytef*)ptr;
|
||||
z_stream->avail_in = len;
|
||||
@ -866,7 +867,7 @@ int gmio_amf_write(
|
||||
(uint8_t*)memblock->ptr + mblock_halfsize,
|
||||
mblock_halfsize,
|
||||
NULL);
|
||||
context.z_crc32 = crc32(0, NULL, 0);
|
||||
context.z_crc32 = gmio_zlib_crc32_initial();
|
||||
context.error =
|
||||
gmio_zlib_compress_init(
|
||||
&context.z_stream, &opts->z_compress_options);
|
||||
|
@ -75,14 +75,21 @@ static const struct tm* gmio_nonnull_datetime(const struct tm* datetime)
|
||||
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)
|
||||
/* Reads 16b uint from memory (little-endian) and advances buffer pos */
|
||||
static uint16_t gmio_adv_decode_uint16_le(const uint8_t** bytes)
|
||||
{
|
||||
gmio_encode_uint64_le(val, bytes);
|
||||
return bytes + 8;
|
||||
const uint16_t val = gmio_decode_uint16_le(*bytes);
|
||||
*bytes += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Reads 32b uint from memory (little-endian) and advances buffer pos */
|
||||
static uint32_t gmio_adv_decode_uint32_le(const uint8_t** bytes)
|
||||
{
|
||||
const uint32_t val = gmio_decode_uint32_le(*bytes);
|
||||
*bytes += 4;
|
||||
return val;
|
||||
}
|
||||
#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)
|
||||
@ -98,25 +105,251 @@ static uint8_t* gmio_adv_encode_uint16_le(uint16_t val, uint8_t* bytes)
|
||||
return bytes + 2;
|
||||
}
|
||||
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
/* Reads 64b uint from memory (little-endian) and advances buffer pos */
|
||||
static uint64_t gmio_adv_decode_uint64_le(const uint8_t** bytes)
|
||||
{
|
||||
const uint64_t val = gmio_decode_uint64_le(*bytes);
|
||||
*bytes += 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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)
|
||||
struct gmio_stream* stream,
|
||||
size_t written,
|
||||
size_t expected,
|
||||
int* ptr_error)
|
||||
{
|
||||
if (error != NULL) {
|
||||
if (ptr_error != NULL) {
|
||||
const bool no_error = written == expected && !gmio_stream_error(stream);
|
||||
*error = no_error ? GMIO_ERROR_OK : GMIO_ERROR_STREAM;
|
||||
*ptr_error = no_error ? GMIO_ERROR_OK : GMIO_ERROR_STREAM;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
static bool gmio_zip_read_checkhelper(
|
||||
struct gmio_stream* stream, size_t read, size_t expected)
|
||||
{
|
||||
return read == expected && !gmio_stream_error(stream);
|
||||
}
|
||||
|
||||
/* Helper to facilitate return from gmio_zip_read_xxx() and gmio_zip_write_xxx()
|
||||
* API functions */
|
||||
static size_t gmio_zip_io_returnerr(size_t io_len, int error, int* ptr_error)
|
||||
{
|
||||
if (ptr_error != NULL)
|
||||
*ptr_error = error;
|
||||
return io_len;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* API functions
|
||||
* ---------- */
|
||||
|
||||
size_t gmio_zip_read_local_file_header(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip_local_file_header *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
uint8_t buff[GMIO_ZIP_SIZE_LOCAL_FILE_HEADER];
|
||||
uint8_t* buffit = buff;
|
||||
|
||||
const size_t read_len = gmio_stream_read_bytes(stream, buff, sizeof(buff));
|
||||
if (!gmio_zip_read_checkhelper(stream, read_len, sizeof(buff)))
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_STREAM, ptr_error);
|
||||
|
||||
/* 4-bytes magic */
|
||||
if (gmio_adv_decode_uint32_le(&buffit) != 0x04034b50) {
|
||||
return gmio_zip_io_returnerr(
|
||||
read_len, GMIO_ZIP_UTILS_ERROR_BAD_MAGIC, ptr_error);
|
||||
}
|
||||
/* 2-bytes version needed to extract */
|
||||
info->version_needed_to_extract = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes general purpose bit flag */
|
||||
info->general_purpose_flags = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes compression method */
|
||||
info->compress_method = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes last mod file time */
|
||||
/* 2-bytes last mod file date */
|
||||
/* TODO: convert DOS datetime to struct tm */
|
||||
const uint32_t dos_datetime = gmio_adv_decode_uint32_le(&buffit);
|
||||
GMIO_UNUSED(dos_datetime);
|
||||
info->lastmod_datetime = NULL;
|
||||
/* 4-bytes crc-32 */
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes compressed size */
|
||||
info->compressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes uncompressed size */
|
||||
info->uncompressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 2-bytes file name length */
|
||||
info->filename_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes extra field length */
|
||||
info->extrafield_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
|
||||
info->filename = NULL;
|
||||
info->extrafield = NULL;
|
||||
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip_write_data_descriptor(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip_data_descriptor *info,
|
||||
int* ptr_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
|
||||
/* TODO: error code */
|
||||
return gmio_zip_io_returnerr(0, GMIO_ERROR_UNKNOWN, ptr_error);
|
||||
#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 {
|
||||
/* TODO: error code */
|
||||
return gmio_zip_io_returnerr(0, GMIO_ERROR_UNKNOWN, ptr_error);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip_read_central_directory_header(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip_central_directory_header *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
uint8_t buff[GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER];
|
||||
uint8_t* buffit = buff;
|
||||
|
||||
const size_t read_len = gmio_stream_read_bytes(stream, buff, sizeof(buff));
|
||||
if (!gmio_zip_read_checkhelper(stream, read_len, sizeof(buff)))
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_STREAM, ptr_error);
|
||||
|
||||
/* 4-bytes magic */
|
||||
if (gmio_adv_decode_uint32_le(&buffit) != 0x02014b50) {
|
||||
return gmio_zip_io_returnerr(
|
||||
read_len, GMIO_ZIP_UTILS_ERROR_BAD_MAGIC, ptr_error);
|
||||
}
|
||||
|
||||
/* 2-bytes version made by */
|
||||
info->version_made_by = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes version needed to extract */
|
||||
info->version_needed_to_extract = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes general purpose bit flag */
|
||||
info->general_purpose_flags = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes compression method */
|
||||
info->compress_method = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes last mod file time */
|
||||
/* 2-bytes last mod file date */
|
||||
/* TODO: convert DOS datetime to struct tm */
|
||||
const uint32_t dos_datetime = gmio_adv_decode_uint32_le(&buffit);
|
||||
GMIO_UNUSED(dos_datetime);
|
||||
info->lastmod_datetime = NULL;
|
||||
/* 4-bytes crc-32 */
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes compressed size */
|
||||
info->compressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes uncompressed size */
|
||||
info->uncompressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 2-bytes file name length */
|
||||
info->filename_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes extra field length */
|
||||
info->extrafield_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes file comment length */
|
||||
info->filecomment_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes disk number start */
|
||||
info->disk_nb_start = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes internal file attributes */
|
||||
info->internal_file_attrs = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 4-bytes external file attributes */
|
||||
info->external_file_attrs = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes relative offset of local header */
|
||||
info->relative_offset_local_header = gmio_adv_decode_uint32_le(&buffit);
|
||||
|
||||
info->filename = NULL;
|
||||
info->extrafield = NULL;
|
||||
info->filecomment = NULL;
|
||||
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip_read_end_of_central_directory_record(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip_end_of_central_directory_record *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
uint8_t buff[GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD];
|
||||
uint8_t* buffit = buff;
|
||||
|
||||
const size_t read_len = gmio_stream_read_bytes(stream, buff, sizeof(buff));
|
||||
if (!gmio_zip_read_checkhelper(stream, read_len, sizeof(buff)))
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_STREAM, ptr_error);
|
||||
|
||||
/* 4-bytes magic */
|
||||
if (gmio_adv_decode_uint32_le(&buffit) != 0x06054b50) {
|
||||
return gmio_zip_io_returnerr(
|
||||
read_len, GMIO_ZIP_UTILS_ERROR_BAD_MAGIC, ptr_error);
|
||||
}
|
||||
|
||||
/* 2-bytes number of this disk */
|
||||
info->disk_nb = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes number of the disk with the start of the central directory */
|
||||
info->disk_nb_with_start_of_central_dir = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes total number of entries in the central directory on this disk */
|
||||
info->total_entry_count_in_central_dir_on_disk =
|
||||
gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 2-bytes total number of entries in the central directory */
|
||||
info->total_entry_count_in_central_dir = gmio_adv_decode_uint16_le(&buffit);
|
||||
/* 4-bytes size of the central directory */
|
||||
info->central_dir_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes offset of start of central directory with respect to the starting
|
||||
* disk number */
|
||||
info->start_offset_central_dir_from_disk_start_nb =
|
||||
gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 2-bytes .ZIP file comment length */
|
||||
info->filecomment_len = gmio_adv_decode_uint16_le(&buffit);
|
||||
|
||||
info->filecomment = NULL;
|
||||
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip_write_local_file_header(
|
||||
struct gmio_stream* stream,
|
||||
const struct gmio_zip_local_file_header* info,
|
||||
int* error)
|
||||
int* ptr_error)
|
||||
{
|
||||
uint8_t fixed_data[GMIO_ZIP_SIZE_LOCAL_FILE_HEADER];
|
||||
uint8_t* buff = fixed_data;
|
||||
@ -162,55 +395,62 @@ size_t gmio_zip_write_local_file_header(
|
||||
written_len +=
|
||||
gmio_stream_write_bytes(stream, info->extrafield, info->extrafield_len);
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, error);
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip_write_data_descriptor(
|
||||
size_t gmio_zip_read_data_descriptor(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip_data_descriptor *info,
|
||||
int* error)
|
||||
struct gmio_zip_data_descriptor *info,
|
||||
int* ptr_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;
|
||||
uint8_t buff[GMIO_ZIP_SIZE_DATA_DESCRIPTOR];
|
||||
uint8_t* buffit = buff;
|
||||
|
||||
const size_t read_len = gmio_stream_read_bytes(stream, buff, sizeof(buff));
|
||||
if (!gmio_zip_read_checkhelper(stream, read_len, sizeof(buff)))
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_STREAM, ptr_error);
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes compressed size */
|
||||
info->compressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 4-bytes uncompressed size */
|
||||
info->uncompressed_size = gmio_adv_decode_uint32_le(&buffit);
|
||||
|
||||
/* 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);
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip64_read_data_descriptor(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_data_descriptor* info,
|
||||
int* ptr_error)
|
||||
{
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
uint8_t buff[GMIO_ZIP64_SIZE_DATA_DESCRIPTOR];
|
||||
uint8_t* buffit = buff;
|
||||
|
||||
const size_t read_len = gmio_stream_read_bytes(stream, buff, sizeof(buff));
|
||||
if (!gmio_zip_read_checkhelper(stream, read_len, sizeof(buff)))
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_STREAM, ptr_error);
|
||||
|
||||
/* 4-bytes crc-32 */
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buffit);
|
||||
/* 8-bytes compressed size */
|
||||
info->compressed_size = gmio_adv_decode_uint64_le(&buffit);
|
||||
/* 8-bytes uncompressed size */
|
||||
info->uncompressed_size = gmio_adv_decode_uint64_le(&buffit);
|
||||
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
#else
|
||||
/* TODO: error code */
|
||||
return gmio_zip_io_returnerr(0, GMIO_ERROR_UNKNOWN, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t gmio_zip_write_central_directory_header(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip_central_directory_header *info,
|
||||
int* error)
|
||||
int* ptr_error)
|
||||
{
|
||||
uint8_t fixed_data[GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER];
|
||||
uint8_t* buff = fixed_data;
|
||||
@ -270,18 +510,18 @@ size_t gmio_zip_write_central_directory_header(
|
||||
written_len +=
|
||||
gmio_stream_write_bytes(stream, info->filecomment, info->filecomment_len);
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, error);
|
||||
stream, written_len, expected_written_len, ptr_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)
|
||||
int* ptr_error)
|
||||
{
|
||||
if (buff_capacity < GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO) {
|
||||
*error = GMIO_ERROR_INVALID_MEMBLOCK_SIZE;
|
||||
return 0;
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_INVALID_MEMBLOCK_SIZE, ptr_error);
|
||||
}
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
/* Tag */
|
||||
@ -297,18 +537,20 @@ size_t gmio_zip64_write_extrafield_extended_info(
|
||||
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;
|
||||
return gmio_zip_io_returnerr(
|
||||
GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO,
|
||||
GMIO_ERROR_OK,
|
||||
ptr_error);
|
||||
#else
|
||||
*error = GMIO_ERROR_UNKNOWN; /* TODO: error code */
|
||||
return 0;
|
||||
/* TODO: error code */
|
||||
return gmio_zip_io_returnerr(0, GMIO_ERROR_UNKNOWN, error);
|
||||
#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)
|
||||
int* ptr_error)
|
||||
{
|
||||
uint8_t fixed_data[GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD];
|
||||
uint8_t* buff = fixed_data;
|
||||
@ -322,17 +564,24 @@ size_t gmio_zip_write_end_of_central_directory_record(
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
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;
|
||||
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 */
|
||||
@ -343,8 +592,11 @@ size_t gmio_zip_write_end_of_central_directory_record(
|
||||
/* 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);
|
||||
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);
|
||||
@ -358,5 +610,5 @@ size_t gmio_zip_write_end_of_central_directory_record(
|
||||
written_len +=
|
||||
gmio_stream_write_bytes(stream, info->filecomment, info->filecomment_len);
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, error);
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
}
|
||||
|
@ -165,10 +165,10 @@ struct gmio_zip_local_file_header {
|
||||
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;
|
||||
const char* filename;
|
||||
const uint8_t* extrafield;
|
||||
};
|
||||
|
||||
/*! Zip data descriptor */
|
||||
@ -246,23 +246,58 @@ struct gmio_zip_write_result {
|
||||
size_t written_len;
|
||||
};
|
||||
|
||||
enum { GMIO_ZIP_UTILS_ERROR_TAG = 0xAA000000 };
|
||||
enum gmio_zip_utils_error {
|
||||
GMIO_ZIP_UTILS_ERROR_BAD_MAGIC = GMIO_ZIP_UTILS_ERROR_TAG + 0x01
|
||||
};
|
||||
|
||||
/*! Reads ZIP local file header from \p stream */
|
||||
size_t gmio_zip_read_local_file_header(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_local_file_header* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads ZIP data descriptor from \p stream */
|
||||
size_t gmio_zip_read_data_descriptor(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_data_descriptor* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads Zip64 data descriptor from \p stream */
|
||||
size_t gmio_zip64_read_data_descriptor(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_data_descriptor* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads ZIP central directory header from \p stream */
|
||||
size_t gmio_zip_read_central_directory_header(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_central_directory_header* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads ZIP end of central directory record from \p stream */
|
||||
size_t gmio_zip_read_end_of_central_directory_record(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip_end_of_central_directory_record* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! 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);
|
||||
int* ptr_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);
|
||||
int* ptr_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);
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes ZIP local file header to \p buff
|
||||
*
|
||||
@ -273,12 +308,12 @@ 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);
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes ZIP end of central directory record \p stream */
|
||||
/*! Writes ZIP end of central directory record to \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);
|
||||
int* ptr_error);
|
||||
|
||||
#endif /* GMIO_INTERNAL_ZIP_UTILS_H */
|
||||
|
@ -30,6 +30,18 @@
|
||||
#include "zlib_utils.h"
|
||||
#include "../error.h"
|
||||
|
||||
/* zlib doc:
|
||||
* the windowBits parameter is the base two logarithm of the window size
|
||||
* (the size of the history buffer). It should be in the range 8..15 for
|
||||
* this version of the library. Larger values of this parameter result in
|
||||
* better compression at the expense of memory usage. The default value is
|
||||
* 15 if deflateInit is used instead.
|
||||
* windowBits can also be –8..–15 for raw deflate. In this case, -windowBits
|
||||
* determines the window size. deflate() will then generate raw deflate
|
||||
* data with no zlib header or trailer, and will not compute an adler32
|
||||
* check value. */
|
||||
static const int z_window_bits_for_no_zlib_wrapper = -15;
|
||||
|
||||
static int gmio_to_zlib_compress_level(int gmio_compress_level)
|
||||
{
|
||||
if (gmio_compress_level == GMIO_ZLIB_COMPRESS_LEVEL_DEFAULT)
|
||||
@ -69,23 +81,12 @@ int gmio_zlib_compress_init(
|
||||
gmio_to_zlib_compress_level(z_opts->level);
|
||||
const int zlib_compress_memusage =
|
||||
gmio_to_zlib_compress_memusage(z_opts->memory_usage);
|
||||
/* zlib doc:
|
||||
* the windowBits parameter is the base two logarithm of the window size
|
||||
* (the size of the history buffer). It should be in the range 8..15 for
|
||||
* this version of the library. Larger values of this parameter result in
|
||||
* better compression at the expense of memory usage. The default value is
|
||||
* 15 if deflateInit is used instead.
|
||||
* windowBits can also be –8..–15 for raw deflate. In this case, -windowBits
|
||||
* determines the window size. deflate() will then generate raw deflate
|
||||
* data with no zlib header or trailer, and will not compute an adler32
|
||||
* check value. */
|
||||
static const int z_window_bits = -15;
|
||||
const int z_init_error =
|
||||
deflateInit2_(
|
||||
z_stream,
|
||||
zlib_compress_level,
|
||||
Z_DEFLATED, /* Method */
|
||||
z_window_bits,
|
||||
z_window_bits_for_no_zlib_wrapper,
|
||||
zlib_compress_memusage,
|
||||
z_opts->strategy,
|
||||
ZLIB_VERSION,
|
||||
@ -104,3 +105,60 @@ bool gmio_check_zlib_compress_options(
|
||||
}
|
||||
return gmio_no_error(*error);
|
||||
}
|
||||
|
||||
int gmio_zlib_uncompress_buffer(
|
||||
uint8_t* dest, size_t* dest_len, const uint8_t* src, size_t src_len)
|
||||
{
|
||||
z_stream stream;
|
||||
int err;
|
||||
|
||||
stream.next_in = (z_const Bytef *)src;
|
||||
stream.avail_in = (uInt)src_len;
|
||||
/* Check for source > 64K on 16-bit machine: */
|
||||
if ((uLong)stream.avail_in != src_len)
|
||||
return GMIO_ERROR_ZLIB_BUF;
|
||||
|
||||
stream.next_out = dest;
|
||||
stream.avail_out = (uInt)*dest_len;
|
||||
if ((uLong)stream.avail_out != *dest_len)
|
||||
return GMIO_ERROR_ZLIB_BUF;
|
||||
|
||||
stream.zalloc = (alloc_func)NULL;
|
||||
stream.zfree = (free_func)NULL;
|
||||
|
||||
err = inflateInit2_(
|
||||
&stream,
|
||||
z_window_bits_for_no_zlib_wrapper,
|
||||
ZLIB_VERSION,
|
||||
sizeof(z_stream));
|
||||
if (err != Z_OK)
|
||||
return err;
|
||||
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
if (err != Z_STREAM_END) {
|
||||
inflateEnd(&stream);
|
||||
if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
|
||||
return GMIO_ERROR_ZLIB_DATA;
|
||||
return err;
|
||||
}
|
||||
*dest_len = stream.total_out;
|
||||
|
||||
err = inflateEnd(&stream);
|
||||
return zlib_error_to_gmio_error(err);
|
||||
}
|
||||
|
||||
uint32_t gmio_zlib_crc32(const uint8_t *buff, size_t buff_len)
|
||||
{
|
||||
return gmio_zlib_crc32_update(gmio_zlib_crc32_initial(), buff, buff_len);
|
||||
}
|
||||
|
||||
uint32_t gmio_zlib_crc32_update(
|
||||
uint32_t crc, const uint8_t *buff, size_t buff_len)
|
||||
{
|
||||
return crc32(crc, (const Bytef*)buff, (uInt)buff_len);
|
||||
}
|
||||
|
||||
uint32_t gmio_zlib_crc32_initial()
|
||||
{
|
||||
return crc32(0, NULL, 0);
|
||||
}
|
||||
|
@ -46,4 +46,24 @@ int gmio_zlib_compress_init(
|
||||
bool gmio_check_zlib_compress_options(
|
||||
int* error, const struct gmio_zlib_compress_options* z_opts);
|
||||
|
||||
/* Decompresses the source buffer into the destination buffer.
|
||||
*
|
||||
* \p sourceLen is the byte length of the source buffer. Upon entry, \p destLen
|
||||
* is the total size of the destination buffer, which must be large enough to
|
||||
* hold the entire uncompressed data.
|
||||
* Upon exit, destLen is the actual size of the compressed buffer.
|
||||
*/
|
||||
int gmio_zlib_uncompress_buffer(
|
||||
uint8_t* dest, size_t* dest_len, const uint8_t* src, size_t src_len);
|
||||
|
||||
/* Computes the CRC-32 value with the bytes buff[0..buff_len-1] */
|
||||
uint32_t gmio_zlib_crc32(const uint8_t* buff, size_t buff_len);
|
||||
|
||||
/* Returns the required initial value for the gmio_zlib_crc32_update() */
|
||||
uint32_t gmio_zlib_crc32_initial();
|
||||
|
||||
/* Updates a running CRC-32 with the bytes buff[0..buff_len-1] */
|
||||
uint32_t gmio_zlib_crc32_update(
|
||||
uint32_t crc, const uint8_t* buff, size_t buff_len);
|
||||
|
||||
#endif /* GMIO_INTERNAL_ZLIB_UTILS_H */
|
||||
|
@ -48,7 +48,8 @@ const char* all_tests()
|
||||
|
||||
gmio_memblock_set_default_constructor(gmio_memblock_for_tests);
|
||||
|
||||
UTEST_RUN(test_amf_write);
|
||||
UTEST_RUN(test_amf_write_doc_null);
|
||||
UTEST_RUN(test_amf_write_doc_1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "../src/gmio_core/internal/byte_codec.h"
|
||||
#include "../src/gmio_core/internal/helper_stream.h"
|
||||
#include "../src/gmio_core/internal/zip_utils.h"
|
||||
#include "../src/gmio_core/internal/zlib_utils.h"
|
||||
#include "../src/gmio_amf/amf_error.h"
|
||||
#include "../src/gmio_amf/amf_io.h"
|
||||
|
||||
@ -178,97 +179,105 @@ static void __tamf__skip_zip_local_file_header()
|
||||
|
||||
}
|
||||
|
||||
static const char* test_amf_write()
|
||||
static const char* test_amf_write_doc_null()
|
||||
{
|
||||
struct gmio_stream stream = {0};
|
||||
struct gmio_amf_document doc = {0};
|
||||
const int error = gmio_amf_write(&stream, &doc, NULL);
|
||||
UTEST_ASSERT(gmio_error(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* test_amf_write_doc_1()
|
||||
{
|
||||
static const size_t wbuffsize = 8192;
|
||||
struct gmio_rw_buffer wbuff = {0};
|
||||
struct gmio_amf_document doc = {0};
|
||||
|
||||
const struct __tamf__material testmaterials[] = {
|
||||
{ { 1., 0., 0. }, "red" },
|
||||
{ { 0., 1., 0. }, "green" },
|
||||
{ { 0., 0., 1. }, "blue" },
|
||||
{ { 1., 1., 1. }, "white" }
|
||||
};
|
||||
|
||||
const struct gmio_vec3d testvertices[] = {
|
||||
{ 0., 0., 0.},
|
||||
{ 1., 0., 0.},
|
||||
{ 1., -1., 0.},
|
||||
{ 0., -1., 0.},
|
||||
{ 1., 0., 1.},
|
||||
{ 1., -1., 1.},
|
||||
{ 0., 0., 1.},
|
||||
{ 0., -1., 1.}
|
||||
};
|
||||
const struct __tamf__triangle testtriangles[] = {
|
||||
{ 0, 1, 2},
|
||||
{ 0, 2, 3},
|
||||
{ 1, 5, 2},
|
||||
{ 1, 4, 5},
|
||||
{ 6, 5, 7},
|
||||
{ 6, 4, 5},
|
||||
{ 0, 6, 7},
|
||||
{ 0, 7, 3},
|
||||
{ 0, 6, 4},
|
||||
{ 0, 4, 1},
|
||||
{ 3, 7, 5},
|
||||
{ 3, 5, 2}
|
||||
};
|
||||
struct __tamf__document testdoc = {0};
|
||||
|
||||
wbuff.ptr = calloc(wbuffsize, 1);
|
||||
wbuff.len = wbuffsize;
|
||||
|
||||
testdoc.vec_material = testmaterials;
|
||||
testdoc.mesh.vec_vertex = testvertices;
|
||||
testdoc.mesh.vertex_count = GMIO_ARRAY_SIZE(testvertices);
|
||||
testdoc.mesh.vec_triangle = testtriangles;
|
||||
testdoc.mesh.triangle_count = GMIO_ARRAY_SIZE(testtriangles);
|
||||
|
||||
doc.cookie = &testdoc;
|
||||
doc.unit = GMIO_AMF_UNIT_MILLIMETER;
|
||||
doc.func_get_document_element = &__tamf__get_document_element;
|
||||
doc.func_get_object_mesh = &__tamf__get_object_mesh;
|
||||
doc.func_get_object_mesh_element = &__tamf__get_object_mesh_element;
|
||||
doc.func_get_object_mesh_volume_triangle =
|
||||
&__tamf__get_object_mesh_volume_triangle;
|
||||
doc.func_get_document_element_metadata =
|
||||
&__tamf__get_document_element_metadata;
|
||||
doc.object_count = 1;
|
||||
doc.material_count = GMIO_ARRAY_SIZE(testmaterials);
|
||||
|
||||
/* Write as raw contents(uncompressed) */
|
||||
{
|
||||
struct gmio_stream stream = {0};
|
||||
struct gmio_amf_document doc = {0};
|
||||
const int error = gmio_amf_write(&stream, &doc, NULL);
|
||||
UTEST_ASSERT(gmio_error(error));
|
||||
struct gmio_stream stream = gmio_stream_buffer(&wbuff);
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
const int error = gmio_amf_write(&stream, &doc, &options);
|
||||
if (gmio_error(error))
|
||||
printf("\n0x%x\n", error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
/* printf("%s\n", wbuff.ptr); */
|
||||
}
|
||||
|
||||
/* Write compressed ZIP */
|
||||
{
|
||||
static const size_t wbuffsize = 8192;
|
||||
struct gmio_rw_buffer wbuff = {0};
|
||||
struct gmio_stream stream = gmio_stream_buffer(&wbuff);
|
||||
struct gmio_amf_document doc = {0};
|
||||
struct gmio_amf_write_options options = {0};
|
||||
const size_t source_len = wbuff.pos;
|
||||
const uint32_t crc32_amf_data = gmio_zlib_crc32(wbuff.ptr, source_len);
|
||||
uint8_t* source = calloc(source_len, 1);
|
||||
memcpy(source, wbuff.ptr, source_len);
|
||||
|
||||
const struct __tamf__material testmaterials[] = {
|
||||
{ { 1., 0., 0. }, "red" },
|
||||
{ { 0., 1., 0. }, "green" },
|
||||
{ { 0., 0., 1. }, "blue" },
|
||||
{ { 1., 1., 1. }, "white" }
|
||||
};
|
||||
const struct gmio_vec3d testvertices[] = {
|
||||
{ 0., 0., 0.},
|
||||
{ 1., 0., 0.},
|
||||
{ 1., -1., 0.},
|
||||
{ 0., -1., 0.},
|
||||
{ 1., 0., 1.},
|
||||
{ 1., -1., 1.},
|
||||
{ 0., 0., 1.},
|
||||
{ 0., -1., 1.}
|
||||
};
|
||||
const struct __tamf__triangle testtriangles[] = {
|
||||
{ 0, 1, 2},
|
||||
{ 0, 2, 3},
|
||||
{ 1, 5, 2},
|
||||
{ 1, 4, 5},
|
||||
{ 6, 5, 7},
|
||||
{ 6, 4, 5},
|
||||
{ 0, 6, 7},
|
||||
{ 0, 7, 3},
|
||||
{ 0, 6, 4},
|
||||
{ 0, 4, 1},
|
||||
{ 3, 7, 5},
|
||||
{ 3, 5, 2}
|
||||
};
|
||||
struct __tamf__document testdoc = {0};
|
||||
|
||||
wbuff.ptr = calloc(wbuffsize, 1);
|
||||
wbuff.len = wbuffsize;
|
||||
|
||||
testdoc.vec_material = testmaterials;
|
||||
testdoc.mesh.vec_vertex = testvertices;
|
||||
testdoc.mesh.vertex_count = GMIO_ARRAY_SIZE(testvertices);
|
||||
testdoc.mesh.vec_triangle = testtriangles;
|
||||
testdoc.mesh.triangle_count = GMIO_ARRAY_SIZE(testtriangles);
|
||||
|
||||
doc.cookie = &testdoc;
|
||||
doc.unit = GMIO_AMF_UNIT_MILLIMETER;
|
||||
doc.func_get_document_element = &__tamf__get_document_element;
|
||||
doc.func_get_object_mesh = &__tamf__get_object_mesh;
|
||||
doc.func_get_object_mesh_element = &__tamf__get_object_mesh_element;
|
||||
doc.func_get_object_mesh_volume_triangle =
|
||||
&__tamf__get_object_mesh_volume_triangle;
|
||||
doc.func_get_document_element_metadata =
|
||||
&__tamf__get_document_element_metadata;
|
||||
doc.object_count = 1;
|
||||
doc.material_count = GMIO_ARRAY_SIZE(testmaterials);
|
||||
|
||||
options.float64_prec = 9;
|
||||
|
||||
/* Write as raw contents(uncompressed) */
|
||||
static const char zip_entry_filename[] = "test.amf";
|
||||
static const uint16_t zip_entry_filename_len =
|
||||
sizeof(zip_entry_filename) - 1;
|
||||
{
|
||||
const int error = gmio_amf_write(&stream, &doc, &options);
|
||||
if (gmio_error(error))
|
||||
printf("\n0x%x\n", error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
/* printf("%s\n", wbuff.ptr); */
|
||||
}
|
||||
|
||||
/* Write compressed ZIP */
|
||||
{
|
||||
const size_t source_len = wbuff.pos;
|
||||
uint8_t* source = calloc(source_len, 1);
|
||||
|
||||
memcpy(source, wbuff.ptr, source_len);
|
||||
wbuff.pos = 0;
|
||||
struct gmio_stream stream = gmio_stream_buffer(&wbuff);
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
options.compress = true;
|
||||
static const char zip_entry_filename[] = "test.amf";
|
||||
options.zip_entry_filename = zip_entry_filename;
|
||||
options.zip_entry_filename_len = sizeof(zip_entry_filename) - 1;
|
||||
options.zip_entry_filename_len = zip_entry_filename_len;
|
||||
const int error = gmio_amf_write(&stream, &doc, &options);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
#if 0
|
||||
@ -276,52 +285,108 @@ static const char* test_amf_write()
|
||||
fwrite(wbuff.ptr, 1, wbuff.pos, file);
|
||||
fclose(file);
|
||||
#endif
|
||||
|
||||
/* Unzip and compare with source data */
|
||||
uint8_t* rbuff = wbuff.ptr;
|
||||
/* -- Read local file header */
|
||||
UTEST_COMPARE_UINT(gmio_decode_uint32_le(rbuff), 0x04034b50);
|
||||
rbuff += 8;
|
||||
/* -- Read compression method */
|
||||
UTEST_COMPARE_UINT(
|
||||
gmio_decode_uint16_le(rbuff),
|
||||
GMIO_ZIP_COMPRESS_METHOD_DEFLATE);
|
||||
rbuff += 18;
|
||||
/* -- Read filename length */
|
||||
UTEST_COMPARE_UINT(
|
||||
gmio_decode_uint16_le(rbuff),
|
||||
options.zip_entry_filename_len);
|
||||
rbuff += 2;
|
||||
/* -- Read extrafield length */
|
||||
const uint16_t zip_extrafield_len = gmio_decode_uint16_le(rbuff);
|
||||
rbuff += 2;
|
||||
/* -- Read filename */
|
||||
UTEST_ASSERT(strncmp(
|
||||
(const char*)rbuff,
|
||||
options.zip_entry_filename,
|
||||
options.zip_entry_filename_len)
|
||||
== 0);
|
||||
rbuff += options.zip_entry_filename_len;
|
||||
/* -- Skip extrafield */
|
||||
rbuff += zip_extrafield_len;
|
||||
|
||||
#if 0 /* TODO: check other ZIP records, and uncompress file */
|
||||
uint8_t* dest = calloc(wbuffsize, 1);
|
||||
unsigned long dest_len = (unsigned long)wbuffsize;
|
||||
const unsigned long z_len = wbuff.pos;
|
||||
const int zerr = uncompress(dest, &dest_len, wbuff.ptr, z_len);
|
||||
printf("\n-- Info: z_len=%i src_len=%i\n", z_len, source_len);
|
||||
UTEST_COMPARE_INT(zerr, Z_OK);
|
||||
UTEST_COMPARE_UINT(source_len, dest_len);
|
||||
UTEST_COMPARE_INT(memcmp(dest, source, source_len), 0);
|
||||
free(dest);
|
||||
#endif
|
||||
|
||||
free(source);
|
||||
}
|
||||
|
||||
free(wbuff.ptr);
|
||||
/* Unzip and compare with source data */
|
||||
{
|
||||
/* Total size in bytes of the ZIP archive */
|
||||
const uintmax_t zip_archive_len = wbuff.pos;
|
||||
wbuff.pos = 0;
|
||||
struct gmio_stream stream = gmio_stream_buffer(&wbuff);
|
||||
int error = GMIO_ERROR_OK;
|
||||
/* -- Read ZIP local file header */
|
||||
struct gmio_zip_local_file_header zip_lfh = {0};
|
||||
const size_t lfh_read_len =
|
||||
gmio_zip_read_local_file_header(&stream, &zip_lfh, &error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_lfh.compress_method,
|
||||
GMIO_ZIP_COMPRESS_METHOD_DEFLATE);
|
||||
UTEST_ASSERT(
|
||||
(zip_lfh.general_purpose_flags &
|
||||
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR)
|
||||
!= 0);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_lfh.filename_len,
|
||||
sizeof(zip_entry_filename) - 1);
|
||||
UTEST_ASSERT(strncmp(
|
||||
(const char*)wbuff.ptr + wbuff.pos,
|
||||
zip_entry_filename,
|
||||
zip_entry_filename_len)
|
||||
== 0);
|
||||
/* -- Read ZIP end of central directory record */
|
||||
static const size_t end_of_central_dir_record_len = 22;
|
||||
wbuff.pos = zip_archive_len - end_of_central_dir_record_len;;
|
||||
struct gmio_zip_end_of_central_directory_record zip_eocdr = {0};
|
||||
gmio_zip_read_end_of_central_directory_record(
|
||||
&stream, &zip_eocdr, &error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
UTEST_COMPARE_UINT(zip_eocdr.disk_nb, 0);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_eocdr.disk_nb_with_start_of_central_dir, 0);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_eocdr.total_entry_count_in_central_dir_on_disk, 1);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_eocdr.total_entry_count_in_central_dir, 1);
|
||||
/* -- Read ZIP central directory */
|
||||
wbuff.pos = zip_eocdr.start_offset_central_dir_from_disk_start_nb;
|
||||
struct gmio_zip_central_directory_header zip_cdh = {0};
|
||||
gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_cdh.compress_method,
|
||||
GMIO_ZIP_COMPRESS_METHOD_DEFLATE);
|
||||
UTEST_ASSERT(
|
||||
(zip_cdh.general_purpose_flags &
|
||||
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR)
|
||||
!= 0);
|
||||
UTEST_COMPARE_UINT(crc32_amf_data, zip_cdh.crc32);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_cdh.filename_len, zip_entry_filename_len);
|
||||
UTEST_ASSERT(strncmp(
|
||||
(const char*)wbuff.ptr + wbuff.pos,
|
||||
zip_entry_filename,
|
||||
zip_entry_filename_len)
|
||||
== 0);
|
||||
/* -- Read compressed AMF data */
|
||||
const size_t pos_start_amf_data =
|
||||
lfh_read_len + zip_lfh.filename_len + zip_lfh.extrafield_len;
|
||||
wbuff.pos = pos_start_amf_data;
|
||||
{
|
||||
uint8_t* dest = calloc(zip_cdh.uncompressed_size, 1);
|
||||
size_t dest_len = zip_cdh.uncompressed_size;
|
||||
const int error =
|
||||
gmio_zlib_uncompress_buffer(
|
||||
dest,
|
||||
&dest_len,
|
||||
(const uint8_t*)wbuff.ptr + wbuff.pos,
|
||||
zip_cdh.compressed_size);
|
||||
printf("\n-- Info: z_len=%i src_len=%i\n",
|
||||
zip_cdh.compressed_size, source_len);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
UTEST_COMPARE_UINT(source_len, dest_len);
|
||||
UTEST_COMPARE_UINT(dest_len, zip_cdh.uncompressed_size);
|
||||
UTEST_COMPARE_INT(memcmp(dest, source, source_len), 0);
|
||||
const uint32_t crc32_uncomp = gmio_zlib_crc32(dest, dest_len);
|
||||
UTEST_COMPARE_UINT(crc32_amf_data, crc32_uncomp);
|
||||
free(dest);
|
||||
}
|
||||
/* -- Read ZIP data descriptor */
|
||||
wbuff.pos = pos_start_amf_data + zip_cdh.compressed_size;
|
||||
struct gmio_zip_data_descriptor zip_dd = {0};
|
||||
gmio_zip_read_data_descriptor(&stream, &zip_dd, &error);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
UTEST_COMPARE_UINT(zip_dd.crc32, crc32_amf_data);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_dd.compressed_size, zip_cdh.compressed_size);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_dd.uncompressed_size, zip_cdh.uncompressed_size);
|
||||
}
|
||||
|
||||
free(source);
|
||||
}
|
||||
|
||||
free(wbuff.ptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user