393 lines
14 KiB
C
393 lines
14 KiB
C
/****************************************************************************
|
|
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
**
|
|
** 2. Redistributions in binary form must reproduce the above
|
|
** copyright notice, this list of conditions and the following
|
|
** disclaimer in the documentation and/or other materials provided
|
|
** with the distribution.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
****************************************************************************/
|
|
|
|
#include "utest_assert.h"
|
|
|
|
#include "core_utils.h"
|
|
#include "stream_buffer.h"
|
|
|
|
#include "../src/gmio_core/error.h"
|
|
#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"
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
|
|
struct __tamf__material
|
|
{
|
|
double color[3];
|
|
const char* name;
|
|
};
|
|
|
|
struct __tamf__triangle
|
|
{
|
|
uint32_t vertex[3];
|
|
};
|
|
|
|
struct __tamf__mesh
|
|
{
|
|
const struct gmio_vec3d* vec_vertex;
|
|
uint32_t vertex_count;
|
|
const struct __tamf__triangle* vec_triangle;
|
|
uint32_t triangle_count;
|
|
};
|
|
|
|
struct __tamf__document
|
|
{
|
|
const struct __tamf__material* vec_material;
|
|
struct __tamf__mesh mesh;
|
|
};
|
|
|
|
static void __tamf__get_document_element(
|
|
const void* cookie,
|
|
enum gmio_amf_document_element element,
|
|
uint32_t element_index,
|
|
void* ptr_element)
|
|
{
|
|
const struct __tamf__document* doc =
|
|
(const struct __tamf__document*)cookie;
|
|
switch (element) {
|
|
case GMIO_AMF_DOCUMENT_ELEMENT_OBJECT: {
|
|
struct gmio_amf_object* ptr_object =
|
|
(struct gmio_amf_object*)ptr_element;
|
|
ptr_object->id = element_index;
|
|
ptr_object->mesh_count = 1;
|
|
break;
|
|
}
|
|
case GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL: {
|
|
struct gmio_amf_material* ptr_material =
|
|
(struct gmio_amf_material*)ptr_element;
|
|
const struct __tamf__material* imat = &doc->vec_material[element_index];
|
|
ptr_material->metadata_count = 1;
|
|
ptr_material->id = element_index;
|
|
ptr_material->color.r = imat->color[0];
|
|
ptr_material->color.g = imat->color[1];
|
|
ptr_material->color.b = imat->color[2];
|
|
break;
|
|
}
|
|
case GMIO_AMF_DOCUMENT_ELEMENT_TEXTURE:
|
|
break;
|
|
case GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION:
|
|
break;
|
|
case GMIO_AMF_DOCUMENT_ELEMENT_METADATA:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void __tamf__get_object_mesh(
|
|
const void* cookie,
|
|
uint32_t object_index,
|
|
uint32_t mesh_index,
|
|
struct gmio_amf_mesh* ptr_mesh)
|
|
{
|
|
GMIO_UNUSED(object_index);
|
|
GMIO_UNUSED(mesh_index);
|
|
const struct __tamf__document* doc =
|
|
(const struct __tamf__document*)cookie;
|
|
ptr_mesh->vertex_count = doc->mesh.vertex_count;
|
|
ptr_mesh->edge_count = 0;
|
|
ptr_mesh->volume_count = 1;
|
|
}
|
|
|
|
static void __tamf__get_object_mesh_element(
|
|
const void* cookie,
|
|
enum gmio_amf_mesh_element element,
|
|
const struct gmio_amf_object_mesh_element_index* element_index,
|
|
void* ptr_element)
|
|
{
|
|
const struct __tamf__document* doc = (const struct __tamf__document*)cookie;
|
|
switch (element) {
|
|
case GMIO_AMF_MESH_ELEMENT_VERTEX: {
|
|
struct gmio_amf_vertex* ptr_vertex = (struct gmio_amf_vertex*)ptr_element;
|
|
ptr_vertex->coords = doc->mesh.vec_vertex[element_index->value];
|
|
break;
|
|
}
|
|
case GMIO_AMF_MESH_ELEMENT_EDGE:
|
|
break;
|
|
case GMIO_AMF_MESH_ELEMENT_VOLUME: {
|
|
struct gmio_amf_volume* ptr_volume = (struct gmio_amf_volume*)ptr_element;
|
|
ptr_volume->materialid = 1;
|
|
ptr_volume->triangle_count = doc->mesh.triangle_count;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void __tamf__get_object_mesh_volume_triangle(
|
|
const void* cookie,
|
|
const struct gmio_amf_object_mesh_element_index* volume_index,
|
|
uint32_t triangle_index,
|
|
struct gmio_amf_triangle* ptr_triangle)
|
|
{
|
|
GMIO_UNUSED(volume_index);
|
|
const struct __tamf__document* doc = (const struct __tamf__document*)cookie;
|
|
const struct __tamf__triangle* tri = &doc->mesh.vec_triangle[triangle_index];
|
|
ptr_triangle->v1 = tri->vertex[0];
|
|
ptr_triangle->v2 = tri->vertex[1];
|
|
ptr_triangle->v3 = tri->vertex[2];
|
|
}
|
|
|
|
static void __tamf__get_document_element_metadata(
|
|
const void* cookie,
|
|
enum gmio_amf_document_element element,
|
|
uint32_t element_index,
|
|
uint32_t metadata_index,
|
|
struct gmio_amf_metadata* ptr_metadata)
|
|
{
|
|
GMIO_UNUSED(metadata_index);
|
|
const struct __tamf__document* doc = (const struct __tamf__document*)cookie;
|
|
if (element == GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL) {
|
|
ptr_metadata->type = "name";
|
|
ptr_metadata->data = doc->vec_material[element_index].name;
|
|
}
|
|
}
|
|
|
|
static void __tamf__skip_zip_local_file_header()
|
|
{
|
|
|
|
}
|
|
|
|
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 = 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);
|
|
#if 0
|
|
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);
|
|
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;
|
|
}
|