gmio_amf: add Zip64 support
This commit is contained in:
parent
cad0804c17
commit
0481df6e61
@ -46,8 +46,8 @@
|
||||
/* Writing(output) context */
|
||||
struct gmio_amf_wcontext
|
||||
{
|
||||
struct gmio_ostringstream sstream;
|
||||
const struct gmio_amf_write_options* options;
|
||||
struct gmio_ostringstream* sstream;
|
||||
const struct gmio_amf_document* document;
|
||||
const struct gmio_task_iface* task_iface;
|
||||
intmax_t task_progress_current;
|
||||
@ -85,7 +85,7 @@ static void gmio_amf_write_double(
|
||||
double value,
|
||||
const char* value_formula)
|
||||
{
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
if (value_formula == NULL || *value_formula == '\0')
|
||||
gmio_ostringstream_write_f64(sstream, value, &context->f64_format);
|
||||
else
|
||||
@ -98,7 +98,7 @@ static void gmio_amf_write_color_component(
|
||||
double value,
|
||||
const char* value_formula)
|
||||
{
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
if (value_formula == NULL || *value_formula == '\0') {
|
||||
gmio_ostringstream_write_f64(sstream, value, &context->f64_format);
|
||||
}
|
||||
@ -114,7 +114,7 @@ static void gmio_amf_write_color(
|
||||
struct gmio_amf_wcontext* context,
|
||||
const struct gmio_amf_color* color)
|
||||
{
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
gmio_ostringstream_write_chararray(sstream, "<color><r>");
|
||||
gmio_amf_write_color_component(context, color->r, color->r_formula);
|
||||
gmio_ostringstream_write_chararray(sstream, "</r><g>");
|
||||
@ -177,7 +177,7 @@ static bool gmio_amf_write_root_metadata(struct gmio_amf_wcontext* context)
|
||||
doc->func_get_document_element(
|
||||
doc->cookie,
|
||||
GMIO_AMF_DOCUMENT_ELEMENT_METADATA, imeta, &metadata);
|
||||
gmio_amf_write_metadata(context->sstream, &metadata);
|
||||
gmio_amf_write_metadata(&context->sstream, &metadata);
|
||||
gmio_amf_wcontext_incr_task_progress(context);
|
||||
}
|
||||
return gmio_no_error(context->error);
|
||||
@ -187,7 +187,7 @@ static bool gmio_amf_write_root_metadata(struct gmio_amf_wcontext* context)
|
||||
static bool gmio_amf_write_root_materials(struct gmio_amf_wcontext* context)
|
||||
{
|
||||
const struct gmio_amf_document* doc = context->document;
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
struct gmio_amf_material material = {0};
|
||||
for (uint32_t imat = 0; imat < doc->material_count; ++imat) {
|
||||
doc->func_get_document_element(
|
||||
@ -280,7 +280,7 @@ static bool gmio_amf_write_mesh(
|
||||
const struct gmio_amf_object_mesh_element_index* base_mesh_element_index)
|
||||
{
|
||||
const struct gmio_amf_document* doc = context->document;
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
struct gmio_amf_object_mesh_element_index mesh_elt_index =
|
||||
*base_mesh_element_index;
|
||||
const struct gmio_ostringstream_format_float* f64_format =
|
||||
@ -441,7 +441,7 @@ static bool gmio_amf_write_mesh(
|
||||
static bool gmio_amf_write_root_objects(struct gmio_amf_wcontext* context)
|
||||
{
|
||||
const struct gmio_amf_document* doc = context->document;
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
struct gmio_amf_object object = {0};
|
||||
for (uint32_t iobj = 0; iobj < doc->object_count; ++iobj) {
|
||||
doc->func_get_document_element(
|
||||
@ -496,7 +496,7 @@ static bool gmio_amf_write_root_objects(struct gmio_amf_wcontext* context)
|
||||
static bool gmio_amf_write_root_textures(struct gmio_amf_wcontext* context)
|
||||
{
|
||||
const struct gmio_amf_document* doc = context->document;
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
struct gmio_amf_texture texture = {0};
|
||||
for (uint32_t itex = 0; itex < doc->texture_count; ++itex) {
|
||||
doc->func_get_document_element(
|
||||
@ -532,7 +532,7 @@ static bool gmio_amf_write_root_textures(struct gmio_amf_wcontext* context)
|
||||
static bool gmio_amf_write_root_constellations(struct gmio_amf_wcontext* context)
|
||||
{
|
||||
const struct gmio_amf_document* doc = context->document;
|
||||
struct gmio_ostringstream* sstream = context->sstream;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
struct gmio_amf_constellation constellation = {0};
|
||||
for (uint32_t icons = 0; icons < doc->constellation_count; ++icons) {
|
||||
doc->func_get_document_element(
|
||||
@ -814,6 +814,39 @@ static struct gmio_zip_entry_filename gmio_amf_zip_entry_filename(
|
||||
return zip_filename;
|
||||
}
|
||||
|
||||
/* Writes AMF file data, plain text or compressed(ZIP)
|
||||
* This function satisfies the signature required by gmio_zip_write_single_file()
|
||||
*/
|
||||
static int gmio_amf_write_file_data(
|
||||
void* cookie, struct gmio_zip_data_descriptor* dd)
|
||||
{
|
||||
struct gmio_amf_wcontext* context = (struct gmio_amf_wcontext*)cookie;
|
||||
struct gmio_ostringstream* sstream = &context->sstream;
|
||||
gmio_amf_write_amf_begin(sstream, context->document);
|
||||
if (!gmio_amf_write_root_metadata(context))
|
||||
return context->error;
|
||||
if (!gmio_amf_write_root_materials(context))
|
||||
return context->error;
|
||||
if (!gmio_amf_write_root_objects(context))
|
||||
return context->error;
|
||||
if (!gmio_amf_write_root_textures(context))
|
||||
return context->error;
|
||||
if (!gmio_amf_write_root_constellations(context))
|
||||
return context->error;
|
||||
if (context->options->compress) {
|
||||
gmio_ostringstream_flush(sstream);
|
||||
context->z_flush = Z_FINISH;
|
||||
}
|
||||
gmio_ostringstream_write_chararray(sstream, "</amf>\n");
|
||||
gmio_ostringstream_flush(sstream);
|
||||
if (context->options->compress && dd != NULL) {
|
||||
dd->crc32 = context->z_crc32;
|
||||
dd->uncompressed_size = context->z_uncompressed_size;
|
||||
dd->compressed_size = context->z_compressed_size;
|
||||
}
|
||||
return context->error;
|
||||
}
|
||||
|
||||
int gmio_amf_write(
|
||||
struct gmio_stream* stream,
|
||||
const struct gmio_amf_document* doc,
|
||||
@ -822,19 +855,10 @@ int gmio_amf_write(
|
||||
static const struct gmio_amf_write_options default_write_opts = {0};
|
||||
opts = opts != NULL ? opts : &default_write_opts;
|
||||
|
||||
/* Constants */
|
||||
struct gmio_amf_wcontext context = {0};
|
||||
struct gmio_memblock_helper mblock_helper =
|
||||
gmio_memblock_helper(opts != NULL ? &opts->stream_memblock : NULL);
|
||||
const struct gmio_memblock* memblock = &mblock_helper.memblock;
|
||||
const struct gmio_zip_entry_filename zip_entry_filename =
|
||||
gmio_amf_zip_entry_filename(opts);
|
||||
|
||||
/* Variables */
|
||||
struct gmio_amf_wcontext context = {0};
|
||||
struct gmio_ostringstream sstream =
|
||||
gmio_ostringstream(
|
||||
*stream, gmio_string(memblock->ptr, 0, memblock->size));
|
||||
uintmax_t zip_write_pos = 0;
|
||||
|
||||
/* Check validity of input parameters */
|
||||
context.error = GMIO_ERROR_OK;
|
||||
@ -847,8 +871,12 @@ int gmio_amf_write(
|
||||
/* Initialize writing context */
|
||||
const struct gmio_string_16 f64_stdio_format =
|
||||
gmio_to_stdio_float_format(opts->float64_format, opts->float64_prec);
|
||||
context.sstream =
|
||||
gmio_ostringstream(
|
||||
*stream, gmio_string(memblock->ptr, 0, memblock->size));
|
||||
context.sstream.cookie = &context;
|
||||
context.sstream.func_stream_write = &gmio_amf_ostringstream_write;
|
||||
context.options = opts;
|
||||
context.sstream = &sstream;
|
||||
context.document = doc;
|
||||
context.task_iface = &opts->task_iface;
|
||||
context.task_progress_current = 0;
|
||||
@ -858,10 +886,11 @@ int gmio_amf_write(
|
||||
context.f64_format.text_format = opts->float64_format;
|
||||
context.f64_format.precision =
|
||||
opts->float64_prec != 0 ? opts->float64_prec : 16;
|
||||
|
||||
if (opts->compress) {
|
||||
/* Initialize internal zlib stream for compression */
|
||||
const size_t mblock_halfsize = memblock->size / 2;
|
||||
context.sstream->strbuff.capacity = mblock_halfsize;
|
||||
context.sstream.strbuff.capacity = mblock_halfsize;
|
||||
context.z_memblock =
|
||||
gmio_memblock(
|
||||
(uint8_t*)memblock->ptr + mblock_halfsize,
|
||||
@ -874,85 +903,23 @@ int gmio_amf_write(
|
||||
if (gmio_error(context.error))
|
||||
goto label_end;
|
||||
context.z_flush = Z_NO_FLUSH;
|
||||
/* Write ZIP file */
|
||||
struct gmio_zip_file_entry file_entry = {0};
|
||||
file_entry.compress_method = GMIO_ZIP_COMPRESS_METHOD_DEFLATE;
|
||||
file_entry.feature_version =
|
||||
opts->force_zip64_format ?
|
||||
GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS :
|
||||
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_DEFLATE;
|
||||
const struct gmio_zip_entry_filename zip_entry_filename =
|
||||
gmio_amf_zip_entry_filename(opts);
|
||||
file_entry.filename = zip_entry_filename.ptr;
|
||||
file_entry.filename_len = zip_entry_filename.len;
|
||||
file_entry.cookie_func_write_file_data = &context;
|
||||
file_entry.func_write_file_data = gmio_amf_write_file_data;
|
||||
gmio_zip_write_single_file(stream, &file_entry, &context.error);
|
||||
}
|
||||
|
||||
sstream.cookie = &context;
|
||||
sstream.func_stream_write = &gmio_amf_ostringstream_write;
|
||||
|
||||
/* If compression enabled, write ZIP local file header */
|
||||
if (opts->compress) {
|
||||
struct gmio_zip_local_file_header info = {0};
|
||||
info.general_purpose_flags =
|
||||
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR;
|
||||
info.compress_method = GMIO_ZIP_COMPRESS_METHOD_DEFLATE;
|
||||
info.filename = zip_entry_filename.ptr;
|
||||
info.filename_len = zip_entry_filename.len;
|
||||
zip_write_pos +=
|
||||
gmio_zip_write_local_file_header(stream, &info, &context.error);
|
||||
if (gmio_error(context.error))
|
||||
goto label_end;
|
||||
}
|
||||
|
||||
gmio_amf_write_amf_begin(&sstream, doc);
|
||||
if (!gmio_amf_write_root_metadata(&context))
|
||||
goto label_end;
|
||||
if (!gmio_amf_write_root_materials(&context))
|
||||
goto label_end;
|
||||
if (!gmio_amf_write_root_objects(&context))
|
||||
goto label_end;
|
||||
if (!gmio_amf_write_root_textures(&context))
|
||||
goto label_end;
|
||||
if (!gmio_amf_write_root_constellations(&context))
|
||||
goto label_end;
|
||||
|
||||
if (opts->compress) {
|
||||
gmio_ostringstream_flush(&sstream);
|
||||
context.z_flush = Z_FINISH;
|
||||
}
|
||||
gmio_ostringstream_write_chararray(&sstream, "</amf>\n");
|
||||
gmio_ostringstream_flush(&sstream);
|
||||
|
||||
/* Write ending ZIP archive data */
|
||||
if (opts->compress && gmio_no_error(context.error)) {
|
||||
zip_write_pos += context.z_compressed_size;
|
||||
/* Write data descriptor */
|
||||
struct gmio_zip_data_descriptor dd = {0};
|
||||
dd.crc32 = context.z_crc32;
|
||||
dd.compressed_size = context.z_compressed_size;
|
||||
dd.uncompressed_size = context.z_uncompressed_size;
|
||||
zip_write_pos +=
|
||||
gmio_zip_write_data_descriptor(stream, &dd, &context.error);
|
||||
if (gmio_error(context.error))
|
||||
goto label_end;
|
||||
/* Write central directory header */
|
||||
struct gmio_zip_central_directory_header cdh = {0};
|
||||
cdh.version_needed_to_extract =
|
||||
GMIO_ZIP_FEATURE_VERSION_FILE_COMPRESSED_DEFLATE;
|
||||
cdh.general_purpose_flags =
|
||||
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR;
|
||||
cdh.compress_method = GMIO_ZIP_COMPRESS_METHOD_DEFLATE;
|
||||
cdh.crc32 = context.z_crc32;
|
||||
cdh.compressed_size = (uint32_t)context.z_compressed_size;
|
||||
cdh.uncompressed_size = (uint32_t)context.z_uncompressed_size;
|
||||
cdh.filename = zip_entry_filename.ptr;
|
||||
cdh.filename_len = zip_entry_filename.len;
|
||||
const uintmax_t central_dir_startpos = zip_write_pos;
|
||||
const size_t central_dir_size =
|
||||
gmio_zip_write_central_directory_header(
|
||||
stream, &cdh, &context.error);
|
||||
zip_write_pos += central_dir_size;
|
||||
if (gmio_error(context.error))
|
||||
goto label_end;
|
||||
/* Write end of central directory record */
|
||||
struct gmio_zip_end_of_central_directory_record eocdr = {0};
|
||||
eocdr.total_entry_count_in_central_dir_on_disk = 1;
|
||||
eocdr.total_entry_count_in_central_dir = 1;
|
||||
eocdr.central_dir_size = (uint32_t)central_dir_size;
|
||||
eocdr.start_offset_central_dir_from_disk_start_nb =
|
||||
(uint32_t)central_dir_startpos;
|
||||
zip_write_pos +=
|
||||
gmio_zip_write_end_of_central_directory_record(
|
||||
stream, &eocdr, &context.error);
|
||||
else {
|
||||
context.error = gmio_amf_write_file_data(&context, NULL);
|
||||
}
|
||||
|
||||
label_end:
|
||||
|
@ -82,6 +82,7 @@ struct gmio_amf_write_options
|
||||
struct gmio_zlib_compress_options z_compress_options;
|
||||
const char* zip_entry_filename;
|
||||
uint16_t zip_entry_filename_len;
|
||||
bool force_zip64_format;
|
||||
};
|
||||
|
||||
#endif /* GMIO_AMF_IO_OPTIONS_H */
|
||||
|
@ -39,9 +39,15 @@
|
||||
|
||||
#include "global.h"
|
||||
|
||||
/*! \c GMIO_ZLIB_ERROR_TAG
|
||||
* Byte-mask to tag(identify) zlib-specific error codes */
|
||||
enum { GMIO_ZLIB_ERROR_TAG = 0x1000000 };
|
||||
enum {
|
||||
/*! \c GMIO_ZLIB_ERROR_TAG
|
||||
* Byte-mask to tag(identify) zlib-specific error codes */
|
||||
GMIO_ZLIB_ERROR_TAG = 0x01000000,
|
||||
|
||||
/*! \c GMIO_ZIP_ERROR_TAG
|
||||
* Byte-mask to tag(identify) ZIP-specific error codes */
|
||||
GMIO_ZIP_ERROR_TAG = 0x02000000
|
||||
};
|
||||
|
||||
/*! Common errors */
|
||||
enum gmio_error
|
||||
@ -97,7 +103,14 @@ enum gmio_error
|
||||
|
||||
/*! Invalid compression memory usage, see
|
||||
* gmio_zlib_compress_options::memory_usage */
|
||||
GMIO_ERROR_ZLIB_INVALID_COMPRESS_MEMORY_USAGE
|
||||
GMIO_ERROR_ZLIB_INVALID_COMPRESS_MEMORY_USAGE,
|
||||
|
||||
/*! Zip64 format requires the compiler to provide a 64b integer type */
|
||||
GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED = GMIO_ZIP_ERROR_TAG + 0x01,
|
||||
|
||||
/*! The size of some ZIP file entry exceeds 32b limit and so requires Zip64
|
||||
* format */
|
||||
GMIO_ERROR_ZIP64_FORMAT_REQUIRED = GMIO_ZIP_ERROR_TAG + 0x02
|
||||
};
|
||||
|
||||
/*! Returns true if <tt>code == GMIO_NO_ERROR</tt> */
|
||||
|
@ -34,8 +34,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*! Stores a mutable string of 8-bit chars
|
||||
*
|
||||
/*! Stores a mutable string of 8-bit chars.
|
||||
* For faster lookups, it knowns the length of its contents. Length must not
|
||||
* exceeds the maximum size(capacity).
|
||||
*/
|
||||
|
@ -41,8 +41,10 @@
|
||||
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_DATA_DESCRIPTOR = 4 + 4 + 4 + 4,
|
||||
GMIO_ZIP64_SIZE_DATA_DESCRIPTOR = 4 + 4 + 2*8,
|
||||
GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 8 + 2*2 + 2*4 + 4*8,
|
||||
GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR = 4 + 4 + 8 + 4,
|
||||
GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 4*2 + 2*4 + 2
|
||||
};
|
||||
|
||||
@ -176,7 +178,7 @@ size_t gmio_zip_write_data_descriptor(
|
||||
uint8_t bytes[GMIO_ZIP64_SIZE_DATA_DESCRIPTOR];
|
||||
uint8_t* buff = bytes;
|
||||
|
||||
/* 4-bytes crc-32 */
|
||||
gmio_adv_encode_uint32_le(0x08074b50, &buff);
|
||||
gmio_adv_encode_uint32_le(info->crc32, &buff);
|
||||
/* Compressed size and uncompressed size (4 or 8 bytes) */
|
||||
if (info->use_zip64) {
|
||||
@ -184,21 +186,19 @@ size_t gmio_zip_write_data_descriptor(
|
||||
gmio_adv_encode_uint64_le(info->compressed_size, &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);
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
else if (!gmio_zip64_required(
|
||||
info->uncompressed_size, info->compressed_size))
|
||||
{
|
||||
gmio_adv_encode_uint32_le((uint32_t)info->compressed_size, &buff);
|
||||
gmio_adv_encode_uint32_le((uint32_t)info->uncompressed_size, &buff);
|
||||
}
|
||||
else {
|
||||
if (info->compressed_size <= UINT32_MAX
|
||||
&& info->uncompressed_size <= UINT32_MAX)
|
||||
{
|
||||
gmio_adv_encode_uint32_le((uint32_t)info->compressed_size, &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);
|
||||
}
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP64_FORMAT_REQUIRED, ptr_error);
|
||||
}
|
||||
|
||||
/* Write to stream */
|
||||
@ -247,6 +247,59 @@ size_t gmio_zip_read_central_directory_header(
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip64_read_end_of_central_directory_record(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip64_end_of_central_directory_record *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
uint8_t bytes[GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD];
|
||||
const uint8_t* buff = bytes;
|
||||
size_t read_len = 0;
|
||||
if (!gmio_zip_readcheckbytes(stream, bytes, sizeof(bytes), &read_len, ptr_error))
|
||||
return read_len;
|
||||
if (!gmio_zip_readcheckmagic(&buff, 0x06064b50, ptr_error))
|
||||
return read_len;
|
||||
gmio_adv_decode_uint64_le(&buff);
|
||||
info->version_made_by = gmio_adv_decode_uint16_le(&buff);
|
||||
info->version_needed_to_extract = gmio_adv_decode_uint16_le(&buff);
|
||||
info->disk_nb = gmio_adv_decode_uint32_le(&buff);
|
||||
info->disk_nb_with_start_of_central_dir = gmio_adv_decode_uint32_le(&buff);
|
||||
info->total_entry_count_in_central_dir_on_disk =
|
||||
gmio_adv_decode_uint64_le(&buff);
|
||||
info->central_dir_size = gmio_adv_decode_uint64_le(&buff);
|
||||
info->start_offset_central_dir_from_disk_start_nb =
|
||||
gmio_adv_decode_uint64_le(&buff);
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
#else
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t gmio_zip64_read_end_of_central_directory_locator(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip64_end_of_central_directory_locator *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
uint8_t bytes[GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR];
|
||||
const uint8_t* buff = bytes;
|
||||
size_t read_len = 0;
|
||||
if (!gmio_zip_readcheckbytes(stream, bytes, sizeof(bytes), &read_len, ptr_error))
|
||||
return read_len;
|
||||
if (!gmio_zip_readcheckmagic(&buff, 0x07064b50, ptr_error))
|
||||
return read_len;
|
||||
info->disk_nb_with_start_of_central_dir = gmio_adv_decode_uint32_le(&buff);
|
||||
info->relative_offset = gmio_adv_decode_uint64_le(&buff);
|
||||
info->total_disk_count = gmio_adv_decode_uint32_le(&buff);
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
#else
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t gmio_zip_read_end_of_central_directory_record(
|
||||
struct gmio_stream *stream,
|
||||
struct gmio_zip_end_of_central_directory_record *info,
|
||||
@ -269,7 +322,6 @@ size_t gmio_zip_read_end_of_central_directory_record(
|
||||
gmio_adv_decode_uint32_le(&buff);
|
||||
info->filecomment_len = gmio_adv_decode_uint16_le(&buff);
|
||||
info->filecomment = NULL;
|
||||
|
||||
return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error);
|
||||
}
|
||||
|
||||
@ -324,6 +376,8 @@ size_t gmio_zip_read_data_descriptor(
|
||||
size_t read_len = 0;
|
||||
if (!gmio_zip_readcheckbytes(stream, bytes, sizeof(bytes), &read_len, ptr_error))
|
||||
return read_len;
|
||||
if (!gmio_zip_readcheckmagic(&buff, 0x08074b50, ptr_error))
|
||||
return read_len;
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buff);
|
||||
info->compressed_size = gmio_adv_decode_uint32_le(&buff);
|
||||
info->uncompressed_size = gmio_adv_decode_uint32_le(&buff);
|
||||
@ -341,13 +395,15 @@ size_t gmio_zip64_read_data_descriptor(
|
||||
size_t read_len = 0;
|
||||
if (!gmio_zip_readcheckbytes(stream, bytes, sizeof(bytes), &read_len, ptr_error))
|
||||
return read_len;
|
||||
if (!gmio_zip_readcheckmagic(&buff, 0x08074b50, ptr_error))
|
||||
return read_len;
|
||||
info->crc32 = gmio_adv_decode_uint32_le(&buff);
|
||||
info->compressed_size = gmio_adv_decode_uint64_le(&buff);
|
||||
info->uncompressed_size = gmio_adv_decode_uint64_le(&buff);
|
||||
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);
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -401,32 +457,86 @@ size_t gmio_zip_write_central_directory_header(
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
}
|
||||
|
||||
size_t gmio_zip64_write_extrafield_extended_info(
|
||||
size_t gmio_zip64_write_extrafield(
|
||||
uint8_t *buff,
|
||||
size_t buff_capacity,
|
||||
const struct gmio_zip64_extrablock_extended_info *info,
|
||||
const struct gmio_zip64_extrafield *info,
|
||||
int* ptr_error)
|
||||
{
|
||||
if (buff_capacity < GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO) {
|
||||
if (buff_capacity < GMIO_ZIP64_SIZE_EXTRAFIELD) {
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_INVALID_MEMBLOCK_SIZE, ptr_error);
|
||||
}
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
/* Tag */
|
||||
gmio_adv_encode_uint16_le(0x0001, &buff);
|
||||
/* Size of the "extra" block */
|
||||
gmio_adv_encode_uint16_le(GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO - 2, &buff);
|
||||
static const uint16_t extrablock_tag = 0x0001;
|
||||
static const uint16_t extrablock_size = 3*8 + 4;
|
||||
gmio_adv_encode_uint16_le(extrablock_tag, &buff);
|
||||
gmio_adv_encode_uint16_le(extrablock_size, &buff);
|
||||
gmio_adv_encode_uint64_le(info->uncompressed_size, &buff);
|
||||
gmio_adv_encode_uint64_le(info->compressed_size, &buff);
|
||||
gmio_adv_encode_uint64_le(info->relative_offset_local_header, &buff);
|
||||
gmio_adv_encode_uint32_le(info->disk_nb_start, &buff);
|
||||
return gmio_zip_io_returnerr(
|
||||
GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO,
|
||||
GMIO_ERROR_OK,
|
||||
ptr_error);
|
||||
GMIO_ZIP64_SIZE_EXTRAFIELD, GMIO_ERROR_OK, ptr_error);
|
||||
#else
|
||||
/* TODO: error code */
|
||||
return gmio_zip_io_returnerr(0, GMIO_ERROR_UNKNOWN, error);
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t gmio_zip64_write_end_of_central_directory_record(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip64_end_of_central_directory_record *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
uint8_t bytes[GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD];
|
||||
uint8_t* buff = bytes;
|
||||
gmio_adv_encode_uint32_le(0x06064b50, &buff);
|
||||
gmio_adv_encode_uint64_le(sizeof(bytes) - 12, &buff);
|
||||
gmio_adv_encode_uint16_le(info->version_made_by, &buff);
|
||||
gmio_adv_encode_uint16_le(info->version_needed_to_extract, &buff);
|
||||
gmio_adv_encode_uint32_le(info->disk_nb, &buff);
|
||||
gmio_adv_encode_uint32_le(info->disk_nb_with_start_of_central_dir, &buff);
|
||||
gmio_adv_encode_uint64_le(
|
||||
info->total_entry_count_in_central_dir_on_disk, &buff);
|
||||
gmio_adv_encode_uint64_le(info->total_entry_count_in_central_dir, &buff);
|
||||
gmio_adv_encode_uint64_le(info->central_dir_size, &buff);
|
||||
gmio_adv_encode_uint64_le(
|
||||
info->start_offset_central_dir_from_disk_start_nb, &buff);
|
||||
/* Write to stream */
|
||||
const size_t expected_written_len = sizeof(bytes);
|
||||
const size_t written_len =
|
||||
gmio_stream_write_bytes(stream, bytes, sizeof(bytes));
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
#else
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t gmio_zip64_write_end_of_central_directory_locator(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip64_end_of_central_directory_locator *info,
|
||||
int *ptr_error)
|
||||
{
|
||||
#ifdef GMIO_HAVE_INT64_TYPE
|
||||
uint8_t bytes[GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR];
|
||||
uint8_t* buff = bytes;
|
||||
gmio_adv_encode_uint32_le(0x07064b50, &buff);
|
||||
gmio_adv_encode_uint32_le(info->disk_nb_with_start_of_central_dir, &buff);
|
||||
gmio_adv_encode_uint64_le(info->relative_offset, &buff);
|
||||
gmio_adv_encode_uint32_le(info->total_disk_count, &buff);
|
||||
/* Write to stream */
|
||||
const size_t expected_written_len = sizeof(bytes);
|
||||
const size_t written_len =
|
||||
gmio_stream_write_bytes(stream, bytes, sizeof(bytes));
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
#else
|
||||
return gmio_zip_io_returnerr(
|
||||
0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -493,3 +603,140 @@ size_t gmio_zip_write_end_of_central_directory_record(
|
||||
return gmio_zip_write_returnhelper(
|
||||
stream, written_len, expected_written_len, ptr_error);
|
||||
}
|
||||
|
||||
bool gmio_zip64_required(
|
||||
uintmax_t uncompressed_size, uintmax_t compressed_size)
|
||||
{
|
||||
return uncompressed_size > UINT32_MAX || compressed_size > UINT32_MAX;
|
||||
}
|
||||
|
||||
bool gmio_zip_write_single_file(
|
||||
struct gmio_stream *stream,
|
||||
const struct gmio_zip_file_entry *file_entry,
|
||||
int *ptr_error)
|
||||
{
|
||||
const bool use_zip64_format_extensions =
|
||||
file_entry->feature_version
|
||||
>= GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS;
|
||||
uint8_t extrafield[GMIO_ZIP64_SIZE_EXTRAFIELD];
|
||||
size_t zip_write_pos = 0;
|
||||
|
||||
/* Write local file header */
|
||||
struct gmio_zip_local_file_header lfh = {0};
|
||||
lfh.general_purpose_flags = GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR;
|
||||
lfh.compress_method = file_entry->compress_method;
|
||||
lfh.filename = file_entry->filename;
|
||||
lfh.filename_len = file_entry->filename_len;
|
||||
if (use_zip64_format_extensions) {
|
||||
const struct gmio_zip64_extrafield zip64extra = {0};
|
||||
zip_write_pos +=
|
||||
gmio_zip64_write_extrafield(
|
||||
extrafield, sizeof(extrafield), &zip64extra, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
lfh.extrafield = extrafield;
|
||||
lfh.extrafield_len = sizeof(extrafield);
|
||||
}
|
||||
zip_write_pos += gmio_zip_write_local_file_header(stream, &lfh, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
|
||||
/* Write file data */
|
||||
struct gmio_zip_data_descriptor dd = {0};
|
||||
*ptr_error =
|
||||
file_entry->func_write_file_data(
|
||||
file_entry->cookie_func_write_file_data, &dd);
|
||||
zip_write_pos += dd.compressed_size;
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
|
||||
/* Guess version needed */
|
||||
const bool needs_zip64 =
|
||||
use_zip64_format_extensions
|
||||
|| gmio_zip64_required(dd.uncompressed_size, dd.compressed_size);
|
||||
const enum gmio_zip_feature_version version_needed =
|
||||
needs_zip64 && !use_zip64_format_extensions ?
|
||||
GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS :
|
||||
file_entry->feature_version;
|
||||
|
||||
/* Write data descriptor */
|
||||
dd.use_zip64 = needs_zip64;
|
||||
zip_write_pos += gmio_zip_write_data_descriptor(stream, &dd, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
|
||||
/* Write central directory header */
|
||||
const uintmax_t pos_start_central_dir = zip_write_pos;
|
||||
struct gmio_zip_central_directory_header cdh = {0};
|
||||
cdh.use_zip64 = needs_zip64;
|
||||
cdh.version_needed_to_extract = version_needed;
|
||||
cdh.general_purpose_flags =
|
||||
GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR;
|
||||
cdh.compress_method = file_entry->compress_method;
|
||||
cdh.crc32 = dd.crc32;
|
||||
cdh.compressed_size = (uint32_t)dd.compressed_size;
|
||||
cdh.uncompressed_size = (uint32_t)dd.uncompressed_size;
|
||||
cdh.filename = file_entry->filename;
|
||||
cdh.filename_len = file_entry->filename_len;
|
||||
if (needs_zip64) {
|
||||
struct gmio_zip64_extrafield zip64extra = {0};
|
||||
zip64extra.compressed_size = dd.compressed_size;
|
||||
zip64extra.uncompressed_size = dd.uncompressed_size;
|
||||
zip64extra.relative_offset_local_header = 0;
|
||||
zip_write_pos +=
|
||||
gmio_zip64_write_extrafield(
|
||||
extrafield, sizeof(extrafield), &zip64extra, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
cdh.extrafield = extrafield;
|
||||
cdh.extrafield_len = sizeof(extrafield);
|
||||
}
|
||||
const uintmax_t central_dir_startpos = zip_write_pos;
|
||||
const size_t central_dir_size =
|
||||
gmio_zip_write_central_directory_header(stream, &cdh, ptr_error);
|
||||
zip_write_pos += central_dir_size;
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
const uintmax_t pos_end_central_dir = zip_write_pos;
|
||||
|
||||
if (needs_zip64) {
|
||||
/* Write Zip64 end of central directory record */
|
||||
struct gmio_zip64_end_of_central_directory_record eocdr64 = {0};
|
||||
eocdr64.version_needed_to_extract = version_needed;
|
||||
eocdr64.total_entry_count_in_central_dir_on_disk = 1;
|
||||
eocdr64.total_entry_count_in_central_dir = 1;
|
||||
eocdr64.central_dir_size =
|
||||
pos_end_central_dir - pos_start_central_dir;
|
||||
eocdr64.start_offset_central_dir_from_disk_start_nb =
|
||||
pos_start_central_dir;
|
||||
zip_write_pos +=
|
||||
gmio_zip64_write_end_of_central_directory_record(
|
||||
stream, &eocdr64, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
|
||||
/* Write Zip64 end of central directory locator */
|
||||
struct gmio_zip64_end_of_central_directory_locator eocdl64 = {0};
|
||||
eocdl64.relative_offset = pos_end_central_dir;
|
||||
eocdl64.total_disk_count = 1;
|
||||
zip_write_pos +=
|
||||
gmio_zip64_write_end_of_central_directory_locator(
|
||||
stream, &eocdl64, ptr_error);
|
||||
if (gmio_error(*ptr_error))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Write end of central directory record */
|
||||
struct gmio_zip_end_of_central_directory_record eocdr = {0};
|
||||
eocdr.use_zip64 = needs_zip64;
|
||||
eocdr.total_entry_count_in_central_dir_on_disk = 1;
|
||||
eocdr.total_entry_count_in_central_dir = 1;
|
||||
eocdr.central_dir_size = (uint32_t)central_dir_size;
|
||||
eocdr.start_offset_central_dir_from_disk_start_nb =
|
||||
(uint32_t)central_dir_startpos;
|
||||
zip_write_pos +=
|
||||
gmio_zip_write_end_of_central_directory_record(
|
||||
stream, &eocdr, ptr_error);
|
||||
|
||||
return gmio_no_error(*ptr_error);
|
||||
}
|
||||
|
@ -203,11 +203,11 @@ struct gmio_zip_central_directory_header {
|
||||
};
|
||||
|
||||
enum {
|
||||
GMIO_ZIP64_SIZE_EXTRAFIELD_EXTENDED_INFO = 2*2 + 3*8 + 4
|
||||
GMIO_ZIP64_SIZE_EXTRAFIELD = 2*2 + 3*8 + 4
|
||||
};
|
||||
|
||||
/*! Zip64 extended info (extra field) */
|
||||
struct gmio_zip64_extrablock_extended_info {
|
||||
struct gmio_zip64_extrafield {
|
||||
uintmax_t compressed_size;
|
||||
uintmax_t uncompressed_size;
|
||||
uintmax_t relative_offset_local_header;
|
||||
@ -229,7 +229,6 @@ struct gmio_zip_end_of_central_directory_record {
|
||||
|
||||
/*! 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;
|
||||
@ -241,6 +240,13 @@ struct gmio_zip64_end_of_central_directory_record {
|
||||
const uint8_t* extensible_data_sector; /* Reserved for use by PKWARE */
|
||||
};
|
||||
|
||||
/*! Zip64 end of central directory locator */
|
||||
struct gmio_zip64_end_of_central_directory_locator {
|
||||
uint32_t disk_nb_with_start_of_central_dir;
|
||||
uintmax_t relative_offset; /* should be 64b */
|
||||
uint32_t total_disk_count;
|
||||
};
|
||||
|
||||
struct gmio_zip_write_result {
|
||||
int error;
|
||||
size_t written_len;
|
||||
@ -275,6 +281,18 @@ size_t gmio_zip_read_central_directory_header(
|
||||
struct gmio_zip_central_directory_header* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads Zip64 end of central directory record from \p stream */
|
||||
size_t gmio_zip64_read_end_of_central_directory_record(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip64_end_of_central_directory_record* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Reads Zip64 end of central directory locator from \p stream */
|
||||
size_t gmio_zip64_read_end_of_central_directory_locator(
|
||||
struct gmio_stream* stream,
|
||||
struct gmio_zip64_end_of_central_directory_locator* 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,
|
||||
@ -299,15 +317,25 @@ size_t gmio_zip_write_central_directory_header(
|
||||
const struct gmio_zip_central_directory_header* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes ZIP local file header to \p buff
|
||||
*
|
||||
/*! Writes Zip64 extra field 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(
|
||||
* \c GMIO_ZIP64_SIZE_EXTRAFIELD */
|
||||
size_t gmio_zip64_write_extrafield(
|
||||
uint8_t* buff,
|
||||
size_t buff_capacity,
|
||||
const struct gmio_zip64_extrablock_extended_info* info,
|
||||
const struct gmio_zip64_extrafield* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes Zip64 end of central directory record to \p stream */
|
||||
size_t gmio_zip64_write_end_of_central_directory_record(
|
||||
struct gmio_stream* stream,
|
||||
const struct gmio_zip64_end_of_central_directory_record* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes Zip64 end of central directory locator to \p stream */
|
||||
size_t gmio_zip64_write_end_of_central_directory_locator(
|
||||
struct gmio_stream* stream,
|
||||
const struct gmio_zip64_end_of_central_directory_locator* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Writes ZIP end of central directory record to \p stream */
|
||||
@ -316,4 +344,25 @@ size_t gmio_zip_write_end_of_central_directory_record(
|
||||
const struct gmio_zip_end_of_central_directory_record* info,
|
||||
int* ptr_error);
|
||||
|
||||
/*! Is Zip64 format required for this file uncompress/compress sizes ? */
|
||||
bool gmio_zip64_required(
|
||||
uintmax_t uncompressed_size, uintmax_t compressed_size);
|
||||
|
||||
/*! Defines a file entry in a ZIP archive */
|
||||
struct gmio_zip_file_entry {
|
||||
enum gmio_zip_compress_method compress_method;
|
||||
enum gmio_zip_feature_version feature_version;
|
||||
const char* filename;
|
||||
uint16_t filename_len;
|
||||
void* cookie_func_write_file_data;
|
||||
int (*func_write_file_data)(
|
||||
void* cookie, struct gmio_zip_data_descriptor* dd);
|
||||
};
|
||||
|
||||
/*! Writes a ZIP archive containing a single file */
|
||||
bool gmio_zip_write_single_file(
|
||||
struct gmio_stream* stream,
|
||||
const struct gmio_zip_file_entry* file_entry,
|
||||
int* ptr_error);
|
||||
|
||||
#endif /* GMIO_INTERNAL_ZIP_UTILS_H */
|
||||
|
@ -49,7 +49,9 @@ const char* all_tests()
|
||||
gmio_memblock_set_default_constructor(gmio_memblock_for_tests);
|
||||
|
||||
UTEST_RUN(test_amf_write_doc_null);
|
||||
UTEST_RUN(test_amf_write_doc_1);
|
||||
UTEST_RUN(test_amf_write_doc_1_plaintext);
|
||||
UTEST_RUN(test_amf_write_doc_1_zip);
|
||||
UTEST_RUN(test_amf_write_doc_1_zip64);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ struct __tamf__mesh
|
||||
struct __tamf__document
|
||||
{
|
||||
const struct __tamf__material* vec_material;
|
||||
uint32_t material_count;
|
||||
struct __tamf__mesh mesh;
|
||||
};
|
||||
|
||||
@ -174,11 +175,6 @@ static void __tamf__get_document_element_metadata(
|
||||
}
|
||||
}
|
||||
|
||||
static void __tamf__skip_zip_local_file_header()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static const char* test_amf_write_doc_null()
|
||||
{
|
||||
struct gmio_stream stream = {0};
|
||||
@ -188,205 +184,382 @@ static const char* test_amf_write_doc_null()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* test_amf_write_doc_1()
|
||||
const struct __tamf__material __tamf__doc_1_materials[] = {
|
||||
{ { 1., 0., 0. }, "red" },
|
||||
{ { 0., 1., 0. }, "green" },
|
||||
{ { 0., 0., 1. }, "blue" },
|
||||
{ { 1., 1., 1. }, "white" }
|
||||
};
|
||||
|
||||
const struct gmio_vec3d __tamf__doc_1_vertices[] = {
|
||||
{ 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 __tamf__doc_1_triangles[] = {
|
||||
{ 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 __tamf__create_doc_1()
|
||||
{
|
||||
struct __tamf__document doc = {0};
|
||||
doc.vec_material = __tamf__doc_1_materials;
|
||||
doc.material_count = GMIO_ARRAY_SIZE(__tamf__doc_1_materials);
|
||||
doc.mesh.vec_vertex = __tamf__doc_1_vertices;
|
||||
doc.mesh.vertex_count = GMIO_ARRAY_SIZE(__tamf__doc_1_vertices);
|
||||
doc.mesh.vec_triangle = __tamf__doc_1_triangles;
|
||||
doc.mesh.triangle_count = GMIO_ARRAY_SIZE(__tamf__doc_1_triangles);
|
||||
return doc;
|
||||
}
|
||||
|
||||
struct gmio_amf_document __tamf_create_doc(
|
||||
const struct __tamf__document* testdoc)
|
||||
{
|
||||
struct gmio_amf_document doc = {0};
|
||||
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 = testdoc->material_count;
|
||||
return doc;
|
||||
}
|
||||
|
||||
static int __tamf__write_amf(
|
||||
struct gmio_rw_buffer* wbuff,
|
||||
const struct gmio_amf_document* doc,
|
||||
const struct gmio_amf_write_options* opts)
|
||||
{
|
||||
struct gmio_stream stream = gmio_stream_buffer(wbuff);
|
||||
return gmio_amf_write(&stream, doc, opts);
|
||||
}
|
||||
|
||||
|
||||
static const char* test_amf_write_doc_1_plaintext()
|
||||
{
|
||||
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 = 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 */
|
||||
{
|
||||
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);
|
||||
|
||||
static const char zip_entry_filename[] = "test.amf";
|
||||
static const uint16_t zip_entry_filename_len =
|
||||
sizeof(zip_entry_filename) - 1;
|
||||
{
|
||||
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;
|
||||
options.zip_entry_filename = zip_entry_filename;
|
||||
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);
|
||||
const struct __tamf__document testdoc = __tamf__create_doc_1();
|
||||
const struct gmio_amf_document doc = __tamf_create_doc(&testdoc);
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
const int error = __tamf__write_amf(&wbuff, &doc, &options);
|
||||
#if 0
|
||||
FILE* file = fopen("output.zip", "wb");
|
||||
fwrite(wbuff.ptr, 1, wbuff.pos, file);
|
||||
fclose(file);
|
||||
if (gmio_error(error))
|
||||
printf("\n0x%x\n", error);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
/* printf("%s\n", wbuff.ptr); */
|
||||
free(wbuff.ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char zip_entry_filename[] = "test.amf";
|
||||
static const uint16_t zip_entry_filename_len = sizeof(zip_entry_filename) - 1;
|
||||
|
||||
static const char* __tamf__check_zip_local_file_header(
|
||||
const struct gmio_zip_local_file_header* zip_lfh)
|
||||
{
|
||||
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,
|
||||
zip_entry_filename_len);
|
||||
UTEST_ASSERT(strncmp(
|
||||
zip_lfh->filename,
|
||||
zip_entry_filename,
|
||||
zip_entry_filename_len)
|
||||
== 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* test_amf_write_doc_1_zip()
|
||||
{
|
||||
static const size_t wbuffsize = 8192;
|
||||
struct gmio_rw_buffer wbuff = {0};
|
||||
wbuff.ptr = calloc(wbuffsize, 1);
|
||||
wbuff.len = wbuffsize;
|
||||
|
||||
const struct __tamf__document testdoc = __tamf__create_doc_1();
|
||||
const struct gmio_amf_document doc = __tamf_create_doc(&testdoc);
|
||||
{ /* Write uncompressed */
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
const int error = __tamf__write_amf(&wbuff, &doc, &options);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
{ /* Write compressed(ZIP) */
|
||||
wbuff.pos = 0;
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
options.compress = true;
|
||||
options.zip_entry_filename = zip_entry_filename;
|
||||
options.zip_entry_filename_len = zip_entry_filename_len;
|
||||
const int error = __tamf__write_amf(&wbuff, &doc, &options);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
#if 1
|
||||
FILE* file = fopen("output.zip", "wb");
|
||||
fwrite(wbuff.ptr, 1, wbuff.pos, file);
|
||||
fclose(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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);
|
||||
zip_lfh.filename = (const char*)wbuff.ptr + wbuff.pos;
|
||||
const char* check_str = __tamf__check_zip_local_file_header(&zip_lfh);
|
||||
if (check_str != NULL)
|
||||
return check_str;
|
||||
/* -- 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;
|
||||
}
|
||||
|
||||
static const char* test_amf_write_doc_1_zip64()
|
||||
{
|
||||
static const size_t wbuffsize = 8192;
|
||||
struct gmio_rw_buffer wbuff = {0};
|
||||
wbuff.ptr = calloc(wbuffsize, 1);
|
||||
wbuff.len = wbuffsize;
|
||||
|
||||
const struct __tamf__document testdoc = __tamf__create_doc_1();
|
||||
const struct gmio_amf_document doc = __tamf_create_doc(&testdoc);
|
||||
{ /* Write uncompressed */
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
const int error = __tamf__write_amf(&wbuff, &doc, &options);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
static const char zip_entry_filename[] = "test.amf";
|
||||
static const uint16_t zip_entry_filename_len = sizeof(zip_entry_filename) - 1;
|
||||
{ /* Write compressed(Zip64) */
|
||||
wbuff.pos = 0;
|
||||
struct gmio_amf_write_options options = {0};
|
||||
options.float64_prec = 9;
|
||||
options.compress = true;
|
||||
options.zip_entry_filename = zip_entry_filename;
|
||||
options.zip_entry_filename_len = zip_entry_filename_len;
|
||||
options.force_zip64_format = true;
|
||||
const int error = __tamf__write_amf(&wbuff, &doc, &options);
|
||||
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
|
||||
#if 1
|
||||
FILE* file = fopen("output_64.zip", "wb");
|
||||
fwrite(wbuff.ptr, 1, wbuff.pos, file);
|
||||
fclose(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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);
|
||||
zip_lfh.filename = (const char*)wbuff.ptr + wbuff.pos;
|
||||
const char* check_str = __tamf__check_zip_local_file_header(&zip_lfh);
|
||||
if (check_str != NULL)
|
||||
return check_str;
|
||||
/* -- 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, 0xFFFF);
|
||||
UTEST_COMPARE_UINT(zip_eocdr.disk_nb_with_start_of_central_dir, 0xFFFF);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_eocdr.total_entry_count_in_central_dir_on_disk, 0xFFFF);
|
||||
UTEST_COMPARE_UINT(zip_eocdr.total_entry_count_in_central_dir, 0xFFFF);
|
||||
UTEST_COMPARE_UINT(zip_eocdr.central_dir_size, 0xFFFFFFFF);
|
||||
UTEST_COMPARE_UINT(
|
||||
zip_eocdr.start_offset_central_dir_from_disk_start_nb,
|
||||
0xFFFFFFFF);
|
||||
#if 0
|
||||
/* -- 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_zip64_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);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(source);
|
||||
free(wbuff.ptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user