gmio_amf: add file format support(export only)

GitHub issue #6
This commit is contained in:
Hugues Delorme 2016-07-29 13:16:25 +02:00
parent 091f665a6d
commit 456eddc520
32 changed files with 3441 additions and 91 deletions

View File

@ -323,8 +323,11 @@ if(MSVC)
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Oi /Qvec-report:2")
# Treat some warnings as errors
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4133")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4024")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4057")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4090")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4133")
# Enable /Zc:strictStrings when msvc_ver > 2012 and build_type != Debug
if((MSVC_VERSION GREATER 1700) AND NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))

View File

@ -43,5 +43,6 @@ build_script:
- cmake --build . --config %CONFIGURATION%
- cmake --build . --target test_core --config %CONFIGURATION%
- cmake --build . --target test_stl --config %CONFIGURATION%
- cmake --build . --target test_amf --config %CONFIGURATION%
- set PATH=%APPVEYOR_BUILD_FOLDER%\build\src\%CONFIGURATION%;%PATH%
- cd tests && ctest . -V -C %CONFIGURATION%

258
src/3rdparty/base64/b64.c vendored Normal file
View File

@ -0,0 +1,258 @@
/*********************************************************************\
MODULE NAME: b64.c
AUTHOR: Bob Trower 2001/08/04
PROJECT: Crypt Data Packaging
COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001
NOTES: This source code may be used as you wish, subject to
the MIT license. See the LICENCE section below.
Canonical source should be at:
http://base64.sourceforge.net
DESCRIPTION:
This little utility implements the Base64
Content-Transfer-Encoding standard described in
RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
This is the coding scheme used by MIME to allow
binary data to be transferred by SMTP mail.
Groups of 3 bytes from a binary stream are coded as
groups of 4 bytes in a text stream.
The input stream is 'padded' with zeros to create
an input that is an even multiple of 3.
A special character ('=') is used to denote padding so
that the stream can be decoded back to its exact size.
Encoded output is formatted in lines which should
be a maximum of 72 characters to conform to the
specification. This program defaults to 72 characters,
but will allow more or less through the use of a
switch. The program enforces a minimum line size
of 4 characters.
Example encoding:
The stream 'ABCD' is 32 bits long. It is mapped as
follows:
ABCD
A (65) B (66) C (67) D (68) (None) (None)
01000001 01000010 01000011 01000100
16 (Q) 20 (U) 9 (J) 3 (D) 17 (R) 0 (A) NA (=) NA (=)
010000 010100 001001 000011 010001 000000 000000 000000
QUJDRA==
Decoding is the process in reverse. A 'decode' lookup
table has been created to avoid string scans.
DESIGN GOALS: Specifically:
Code is a stand-alone utility to perform base64
encoding/decoding. It should be genuinely useful
when the need arises and it meets a need that is
likely to occur for some users.
Code acts as sample code to show the author's
design and coding style.
Generally:
This program is designed to survive:
Everything you need is in a single source file.
It compiles cleanly using a vanilla ANSI C compiler.
It does its job correctly with a minimum of fuss.
The code is not overly clever, not overly simplistic
and not overly verbose.
Access is 'cut and paste' from a web page.
Terms of use are reasonable.
VALIDATION: Non-trivial code is never without errors. This
file likely has some problems, since it has only
been tested by the author. It is expected with most
source code that there is a period of 'burn-in' when
problems are identified and corrected. That being
said, it is possible to have 'reasonably correct'
code by following a regime of unit test that covers
the most likely cases and regression testing prior
to release. This has been done with this code and
it has a good probability of performing as expected.
Unit Test Cases:
case 0:empty file:
CASE0.DAT -> ->
(Zero length target file created
on both encode and decode.)
case 1:One input character:
CASE1.DAT A -> QQ== -> A
case 2:Two input characters:
CASE2.DAT AB -> QUI= -> AB
case 3:Three input characters:
CASE3.DAT ABC -> QUJD -> ABC
case 4:Four input characters:
case4.dat ABCD -> QUJDRA== -> ABCD
case 5:All chars from 0 to ff, linesize set to 50:
AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj
JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH
SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr
bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P
kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz
tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX
2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7
/P3+/w==
case 6:Mime Block from e-mail:
(Data same as test case 5)
case 7: Large files:
Tested 28 MB file in/out.
case 8: Random Binary Integrity:
This binary program (b64.exe) was encoded to base64,
back to binary and then executed.
case 9 Stress:
All files in a working directory encoded/decoded
and compared with file comparison utility to
ensure that multiple runs do not cause problems
such as exhausting file handles, tmp storage, etc.
-------------
Syntax, operation and failure:
All options/switches tested. Performs as
expected.
case 10:
No Args -- Shows Usage Screen
Return Code 1 (Invalid Syntax)
case 11:
One Arg (invalid) -- Shows Usage Screen
Return Code 1 (Invalid Syntax)
case 12:
One Arg Help (-?) -- Shows detailed Usage Screen.
Return Code 0 (Success -- help request is valid).
case 13:
One Arg Help (-h) -- Shows detailed Usage Screen.
Return Code 0 (Success -- help request is valid).
case 14:
One Arg (valid) -- Uses stdin/stdout (filter)
Return Code 0 (Sucess)
case 15:
Two Args (invalid file) -- shows system error.
Return Code 2 (File Error)
case 16:
Encode non-existent file -- shows system error.
Return Code 2 (File Error)
case 17:
Out of disk space -- shows system error.
Return Code 3 (File I/O Error)
case 18:
Too many args -- shows system error.
Return Code 1 (Invalid Syntax)
-------------
Compile/Regression test:
gcc compiled binary under Cygwin
Microsoft Visual Studio under Windows 2000
Microsoft Version 6.0 C under Windows 2000
DEPENDENCIES: None
LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall
be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
VERSION HISTORY:
Bob Trower 2001/08/04 -- Create Version 0.00.00B
Bob Trower 2001/08/17 -- Correct documentation, messages.
-- Correct help for linesize syntax.
-- Force error on too many arguments.
Bob Trower 2001/08/19 -- Add sourceforge.net reference to
help screen prior to release.
Bob Trower 2004/10/22 -- Cosmetics for package/release.
Bob Trower 2008/02/28 -- More Cosmetics for package/release.
Bob Trower 2011/02/14 -- Cast altered to fix warning in VS6.
Bob Trower 2015/10/29 -- Change *bug* from 0 to EOF in putc
invocation. BIG shout out to people
reviewing on sourceforge,
particularly rachidc, jorgeventura
and zeroxia.
-- Change date format to conform with
latest convention.
\******************************************************************* */
#include "b64.h"
/*
** Translation Table as described in RFC1113
*/
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
** Translation Table to decode (created by author)
*/
static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
/*
** encodeblock
**
** encode 3 8-bit binary bytes as 4 '6-bit' characters
*/
void b64_encodeblock( const unsigned char *in, unsigned char *out, size_t len )
{
out[0] = (unsigned char) cb64[ (int)(in[0] >> 2) ];
out[1] = (unsigned char) cb64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ];
out[2] = (unsigned char) (len > 1 ? cb64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '=');
out[3] = (unsigned char) (len > 2 ? cb64[ (int)(in[2] & 0x3f) ] : '=');
}
/*
** decodeblock
**
** decode 4 '6-bit' characters into 3 8-bit binary bytes
*/
void b64_decodeblock( const unsigned char *in, unsigned char *out )
{
out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
}

9
src/3rdparty/base64/b64.h vendored Normal file
View File

@ -0,0 +1,9 @@
#ifndef BASE64_B64_H
#define BASE64_B64_H
#include <stddef.h>
void b64_encodeblock(const unsigned char* in, unsigned char* out, size_t len);
void b64_decodeblock(const unsigned char* in, unsigned char* out);
#endif /* BASE64_B64_H */

293
src/3rdparty/miloyip_itoa/branchlut.c vendored Normal file
View File

@ -0,0 +1,293 @@
/*
* Original code from Milo Yip
* https://github.com/miloyip/itoa-benchmark/src/branchlut.cpp
* commit #27c6059
*
* Adapted to be C90 compatible
*/
#include "branchlut.h"
static const char gDigitsLut[200] = {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
};
/*
* Branching for different cases (forward)
* Use lookup table of two digits
*/
char* u32toa_branchlut(uint32_t value, char* buffer) {
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
if (value >= 1000)
*buffer++ = gDigitsLut[d1];
if (value >= 100)
*buffer++ = gDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
}
else if (value < 100000000) {
/* value = bbbbcccc */
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = gDigitsLut[d1];
if (value >= 1000000)
*buffer++ = gDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
*buffer++ = gDigitsLut[d3];
*buffer++ = gDigitsLut[d3 + 1];
*buffer++ = gDigitsLut[d4];
*buffer++ = gDigitsLut[d4 + 1];
}
else {
/* value = aabbbbcccc in decimal */
const uint32_t a = value / 100000000; /* 1 to 42 */
value %= 100000000;
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = gDigitsLut[i];
*buffer++ = gDigitsLut[i + 1];
}
else
*buffer++ = '0' + (char)a;
{
const uint32_t b = value / 10000; /* 0 to 9999 */
const uint32_t c = value % 10000; /* 0 to 9999 */
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
*buffer++ = gDigitsLut[d1];
*buffer++ = gDigitsLut[d1 + 1];
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
*buffer++ = gDigitsLut[d3];
*buffer++ = gDigitsLut[d3 + 1];
*buffer++ = gDigitsLut[d4];
*buffer++ = gDigitsLut[d4 + 1];
}
}
/**buffer++ = '\0';*/
return buffer;
}
char* i32toa_branchlut(int32_t value, char* buffer) {
uint32_t u = (uint32_t)value;
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u32toa_branchlut(u, buffer);
}
#ifdef GMIO_HAVE_INT64_TYPE
/* C90 does not support ULL literals */
#define GMIO_UINT64_C(high32, low32) (((uint64_t)(high32) << 32) | (low32))
static const uint64_t one_e16 = GMIO_UINT64_C(0x002386f2, 0x6fc10000);
static const uint64_t one_e15 = GMIO_UINT64_C(0x00038d7e, 0xa4c68000);
static const uint64_t one_e14 = GMIO_UINT64_C(0x00005af3, 0x107a4000);
static const uint64_t one_e13 = GMIO_UINT64_C(0x00000918, 0x4e72a000);
static const uint64_t one_e12 = GMIO_UINT64_C(0x000000e8, 0xd4a51000);
static const uint64_t one_e11 = GMIO_UINT64_C(0x00000017, 0x4876e800);
static const uint64_t one_e10 = GMIO_UINT64_C(0x00000002, 0x540be400);
char* u64toa_branchlut(uint64_t value, char* buffer) {
if (value < 100000000) {
uint32_t v = (uint32_t)value;
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000)
*buffer++ = gDigitsLut[d1];
if (v >= 100)
*buffer++ = gDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
}
else {
/* value = bbbbcccc */
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = gDigitsLut[d1];
if (value >= 1000000)
*buffer++ = gDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
*buffer++ = gDigitsLut[d3];
*buffer++ = gDigitsLut[d3 + 1];
*buffer++ = gDigitsLut[d4];
*buffer++ = gDigitsLut[d4 + 1];
}
}
else if (value < one_e16) {
const uint32_t v0 = (uint32_t)(value / 100000000);
const uint32_t v1 = (uint32_t)(value % 100000000);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if (value >= one_e15)
*buffer++ = gDigitsLut[d1];
if (value >= one_e14)
*buffer++ = gDigitsLut[d1 + 1];
if (value >= one_e13)
*buffer++ = gDigitsLut[d2];
if (value >= one_e12)
*buffer++ = gDigitsLut[d2 + 1];
if (value >= one_e11)
*buffer++ = gDigitsLut[d3];
if (value >= one_e10)
*buffer++ = gDigitsLut[d3 + 1];
if (value >= 1000000000)
*buffer++ = gDigitsLut[d4];
if (value >= 100000000)
*buffer++ = gDigitsLut[d4 + 1];
*buffer++ = gDigitsLut[d5];
*buffer++ = gDigitsLut[d5 + 1];
*buffer++ = gDigitsLut[d6];
*buffer++ = gDigitsLut[d6 + 1];
*buffer++ = gDigitsLut[d7];
*buffer++ = gDigitsLut[d7 + 1];
*buffer++ = gDigitsLut[d8];
*buffer++ = gDigitsLut[d8 + 1];
}
else {
const uint32_t a = (uint32_t)(value / one_e16); /* 1 to 1844 */
value %= one_e16;
if (a < 10)
*buffer++ = '0' + (char)a;
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = gDigitsLut[i];
*buffer++ = gDigitsLut[i + 1];
}
else if (a < 1000) {
const uint32_t i = (a % 100) << 1;
*buffer++ = '0' + (char)(a / 100);
*buffer++ = gDigitsLut[i];
*buffer++ = gDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = gDigitsLut[i];
*buffer++ = gDigitsLut[i + 1];
*buffer++ = gDigitsLut[j];
*buffer++ = gDigitsLut[j + 1];
}
{
const uint32_t v0 = (uint32_t)(value / 100000000);
const uint32_t v1 = (uint32_t)(value % 100000000);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = gDigitsLut[d1];
*buffer++ = gDigitsLut[d1 + 1];
*buffer++ = gDigitsLut[d2];
*buffer++ = gDigitsLut[d2 + 1];
*buffer++ = gDigitsLut[d3];
*buffer++ = gDigitsLut[d3 + 1];
*buffer++ = gDigitsLut[d4];
*buffer++ = gDigitsLut[d4 + 1];
*buffer++ = gDigitsLut[d5];
*buffer++ = gDigitsLut[d5 + 1];
*buffer++ = gDigitsLut[d6];
*buffer++ = gDigitsLut[d6 + 1];
*buffer++ = gDigitsLut[d7];
*buffer++ = gDigitsLut[d7 + 1];
*buffer++ = gDigitsLut[d8];
*buffer++ = gDigitsLut[d8 + 1];
}
}
/**buffer++ = '\0';*/
return buffer;
}
char* i64toa_branchlut(int64_t value, char* buffer) {
uint64_t u = (uint64_t)value;
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u64toa_branchlut(u, buffer);
}
#endif /* GMIO_HAVE_INT64_TYPE */

13
src/3rdparty/miloyip_itoa/branchlut.h vendored Normal file
View File

@ -0,0 +1,13 @@
#ifndef MILOYIP_ITOA_BRANCHLUT_H
#define MILOYIP_ITOA_BRANCHLUT_H
#include "../../gmio_core/global.h"
char* u32toa_branchlut(uint32_t value, char* buffer);
char* i32toa_branchlut(int32_t value, char* buffer);
#ifdef GMIO_HAVE_INT64_TYPE
char* u64toa_branchlut(uint64_t value, char* buffer);
char* i64toa_branchlut(int64_t value, char* buffer);
#endif
#endif /* MILOYIP_ITOA_BRANCHLUT_H */

View File

@ -39,6 +39,12 @@ file(GLOB GMIO_SRC_FILES gmio_core/* gmio_core/internal/*)
if(GMIO_STR2FLOAT_LIBCODE EQUAL 2 OR GMIO_FLOAT2STR_LIBCODE EQUAL 2)
file(GLOB GMIO_3RDPARTY_FILES 3rdparty/double-conversion/*)
endif()
set(GMIO_3RDPARTY_FILES
${GMIO_3RDPARTY_FILES}
3rdparty/miloyip_itoa/branchlut.h
3rdparty/miloyip_itoa/branchlut.c
3rdparty/base64/b64.h
3rdparty/base64/b64.c)
set(GMIO_SRC_FILES ${GMIO_SRC_FILES} ${GMIO_3RDPARTY_FILES})
configure_file(gmio_core/version.h.cmake gmio_core/version.h @ONLY)
@ -59,6 +65,12 @@ set(GMIO_SRC_FILES ${GMIO_SRC_FILES} ${GMIO_LIBSTL_SRC_FILES})
file(GLOB GMIO_LIBSTL_HEADERS gmio_stl/*.h)
install(FILES ${GMIO_LIBSTL_HEADERS} DESTINATION include/gmio_stl)
# Module libAMF
file(GLOB GMIO_LIBAMF_SRC_FILES gmio_amf/* gmio_amf/internal/*)
set(GMIO_SRC_FILES ${GMIO_SRC_FILES} ${GMIO_LIBAMF_SRC_FILES})
file(GLOB GMIO_LIBAMF_HEADERS gmio_amf/*.h)
install(FILES ${GMIO_LIBAMF_HEADERS} DESTINATION include/gmio_amf)
# Common for support modules
install(FILES gmio_support/support_global.h DESTINATION include/gmio_support)

367
src/gmio_amf/amf_document.h Normal file
View File

@ -0,0 +1,367 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file amf_document.h
* Structures for AMF document
*
* \addtogroup gmio_amf
* @{
*/
#ifndef GMIO_AMF_DOCUMENT_H
#define GMIO_AMF_DOCUMENT_H
#include "amf_global.h"
#include "../gmio_core/endian.h"
#include "../gmio_core/memblock.h"
#include "../gmio_core/vecgeom.h"
#include <stddef.h>
struct gmio_amf_metadata
{
const char* type; /* UTF8-encoded */
const char* data; /* UTF8-encoded */
};
struct gmio_amf_color
{
double r; /* in [0,1] */
double g; /* in [0,1] */
double b; /* in [0,1] */
double a; /* in [0,1] optional */
const char* r_formula;
const char* g_formula;
const char* b_formula;
const char* a_formula;
};
struct gmio_amf_material
{
uint32_t id; /* XML:integer */
struct gmio_amf_color color;
uint32_t composite_count;
uint32_t metadata_count;
};
struct gmio_amf_composite
{
uint32_t materialid; /* XML:nonNegativeInteger, required */
double value; /* governs the percent of material */
const char* value_formula;
};
struct gmio_amf_vertex
{
struct gmio_vec3d coords;
bool has_normal;
struct gmio_vec3d normal; /* XML:NegOneToOne: -1 <= coord <= 1 */
bool has_color;
struct gmio_amf_color color; /* XML:Color */
uint32_t metadata_count;
};
struct gmio_amf_edge
{
uint32_t v1; /* XML:nonNegativeInteger */
uint32_t v2; /* XML:nonNegativeInteger */
/* Direction vectors */
struct gmio_vec3d d1; /* XML:NegOneToOne: -1 <= coord <= 1 */
struct gmio_vec3d d2; /* XML:NegOneToOne: -1 <= coord <= 1 */
};
struct gmio_amf_texmap
{
uint32_t rtexid; /* XML:nonNegativeInteger */
uint32_t gtexid; /* XML:nonNegativeInteger */
uint32_t btexid; /* XML:nonNegativeInteger */
uint32_t atexid; /* XML:nonNegativeInteger */
struct gmio_vec3d utex; /* XML:Coords : any value */
struct gmio_vec3d vtex; /* XML:Coords : any value */
bool has_wtex;
struct gmio_vec3d wtex; /* XML:Coords : any value */
};
struct gmio_amf_triangle
{
uint32_t v1; /* XML:nonNegativeInteger */
uint32_t v2; /* XML:nonNegativeInteger */
uint32_t v3; /* XML:nonNegativeInteger */
bool has_texmap;
struct gmio_amf_texmap texmap; /* XML:TexMap */
bool has_color;
struct gmio_amf_color color; /* XML:Color */
};
enum gmio_amf_volume_type
{
GMIO_AMF_VOLUME_TYPE_OBJECT = 0,
GMIO_AMF_VOLUME_TYPE_SUPPORT
};
struct gmio_amf_volume
{
uint32_t materialid; /* XML:nonNegativeInteger */
enum gmio_amf_volume_type type;
uint32_t triangle_count; /* Should be >= 4 */
uint32_t metadata_count;
bool has_color;
struct gmio_amf_color color; /* XML:Color */
};
struct gmio_amf_mesh
{
uint32_t vertex_count;
uint32_t edge_count;
uint32_t volume_count;
};
struct gmio_amf_object
{
uint32_t id; /* XML:integer */
uint32_t mesh_count;
uint32_t metadata_count;
bool has_color;
struct gmio_amf_color color; /* XML:Color */
};
struct gmio_amf_constellation
{
uint32_t id; /* XML:integer */
uint32_t instance_count; /* Should be >= 2 */
uint32_t metadata_count;
};
struct gmio_amf_instance
{
uint32_t objectid; /* XML:nonNegativeInteger */
struct gmio_vec3d delta; /* Any value */
struct gmio_vec3d rot; /* XML:Degrees: -360 <= coord < 360 */
};
enum gmio_amf_texture_type
{
GMIO_AMF_TEXTURE_TYPE_GRAYSCALE
};
struct gmio_amf_texture
{
uint32_t id; /* XML:integer */
uint32_t width; /* XML:nonNegativeInteger */
uint32_t height; /* XML:nonNegativeInteger */
uint32_t depth; /* XML:nonNegativeInteger */
bool tiled;
enum gmio_amf_texture_type type;
struct gmio_memblock binary_data; /* Will be converted to base64 */
};
enum gmio_amf_unit
{
GMIO_AMF_UNIT_UNKNOWN,
GMIO_AMF_UNIT_MILLIMETER,
GMIO_AMF_UNIT_INCH,
GMIO_AMF_UNIT_FEET,
GMIO_AMF_UNIT_METER,
GMIO_AMF_UNIT_MICRON
};
enum gmio_amf_document_element
{
GMIO_AMF_DOCUMENT_ELEMENT_OBJECT,
GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL,
GMIO_AMF_DOCUMENT_ELEMENT_TEXTURE,
GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION,
GMIO_AMF_DOCUMENT_ELEMENT_METADATA
};
enum gmio_amf_mesh_element
{
GMIO_AMF_MESH_ELEMENT_VERTEX,
GMIO_AMF_MESH_ELEMENT_EDGE,
GMIO_AMF_MESH_ELEMENT_VOLUME
};
struct gmio_amf_object_mesh_element_index
{
uint32_t object_index;
uint32_t mesh_index;
uint32_t value;
};
/* Note: version is 1.2 */
struct gmio_amf_document
{
/*! Opaque pointer on the user AMF document, passed as first argument to
* hook functions */
const void* cookie;
enum gmio_amf_unit unit;
uint32_t object_count; /* Must be >= 1 */
uint32_t material_count;
uint32_t texture_count;
uint32_t constellation_count;
uint32_t metadata_count;
/*! Pointer on a function that retrieves the i-th document sub-element
*
* \p element is the type of the sub-element of interest.\n
* \p element_index is the index of the sub-element within the AMF
* document.\n
* The domain of this index depends on \p element :
* <table>
* <tr> <th>Element type</th> <th>Domain of index</th> </tr>
* <tr> <td>OBJECT</td> <td><tt>[0 .. object_count[</tt></td>
* <tr> <td>MATERIAL</td> <td><tt>[0 .. material_count[</tt></td>
* <tr> <td>TEXTURE</td> <td><tt>[0 .. texture_count[</tt></td>
* <tr> <td>CONSTELLATION</td> <td><tt>[0 .. constellation_count[</tt></td>
* <tr> <td>METADATA</td> <td><tt>[0 .. metadata_count[</tt></td>
* </table>
*
* <table>
* <tr> <th>Element type</th> <th>gmio type</th> </tr>
* <tr> <td>OBJECT</td> <td>gmio_amf_object</td>
* <tr> <td>MATERIAL</td> <td>gmio_amf_material</td>
* <tr> <td>TEXTURE</td> <td>gmio_amf_texture</td>
* <tr> <td>CONSTELLATION</td> <td>gmio_amf_constellation</td>
* <tr> <td>METADATA</td> <td>gmio_amf_metadata</td>
* </table>
*/
void (*func_get_document_element)(
const void* cookie,
enum gmio_amf_document_element element,
uint32_t element_index,
void* ptr_element);
/*! Pointer on a function that retrieves the i-th \c composite within a
* \c material element */
void (*func_get_material_composite)(
const void* cookie,
uint32_t material_index,
uint32_t composite_index,
struct gmio_amf_composite* ptr_composite);
/*! Pointer on a function that retrieves the i-th \c instance within a
* \c constellation element */
void (*func_get_constellation_instance)(
const void* cookie,
uint32_t constellation_index,
uint32_t instance_index,
struct gmio_amf_instance* ptr_instance);
/*! Pointer on a function that retrieves the i-th \c mesh within an
* \c object element */
void (*func_get_object_mesh)(
const void* cookie,
uint32_t object_index,
uint32_t mesh_index,
struct gmio_amf_mesh* ptr_mesh);
/*! Pointer on a function that retrieves the i-th sub-element of a \c mesh
* element
*
* \p element is the type of the sub-element of interest.\n
* \p element_index is the index of the sub-element within the \c mesh
* element.\n
* The domain of this index(ie. \c value field) depends on \p element :
* <table>
* <tr> <th>Element type</th> <th>Domain of index</th> </tr>
* <tr> <td>VERTEX</td> <td><tt>[0 .. gmio_amf_mesh::vertex_count[</tt></td>
* <tr> <td>EDGE</td> <td><tt>[0 .. gmio_amf_mesh::edge_count[</tt></td>
* <tr> <td>VOLUME</td> <td><tt>[0 .. gmio_amf_mesh::volume_count[</tt></td>
* </table>
*
* The concrete type of \p ptr_struct_element depends on \p element :
* <table>
* <tr> <th>Element type</th> <th>gmio type</th> </tr>
* <tr> <td>VERTEX</td> <td>gmio_amf_vertex</td>
* <tr> <td>EDGE</td> <td>gmio_amf_edge</td>
* <tr> <td>VOLUME</td> <td>gmio_amf_volume</td>
* </table>
*/
void (*func_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);
/*! Pointer on a function that retrieves the i-th \c triangle within a
* mesh \c volume element */
void (*func_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);
/* Function pointers to retrieve metadata */
/*! Pointer on a function that retrieves the i-th metadata assigned to a
* document sub-element(being \c material, \c object or \c constellation )
*
* \p element is the type of the sub-element of interest, it can
* take one of this value :
* \li GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL
* \li GMIO_AMF_DOCUMENT_ELEMENT_OBJECT
* \li GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION
*
* \p element_index is the index of the sub-element within the AMF
* document.\n
* The domain of this index depends on \p element :
* <table>
* <tr> <th>Element type</th> <th>Domain of index</th> </tr>
* <tr> <td>MATERIAL</td> <td><tt>[0 .. material_count[</tt></td>
* <tr> <td>OBJECT</td> <td><tt>[0 .. object_count[</tt></td>
* <tr> <td>CONSTELLATION</td> <td><tt>[0 .. constellation_count[</tt></td>
* </table>
*/
void (*func_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);
/*! Pointer on a function that retrieves the i-th metadata assigned to a
* mesh vertex */
void (*func_get_object_mesh_vertex_metadata)(
const void* cookie,
const struct gmio_amf_object_mesh_element_index* vertex_index,
uint32_t metadata_index,
struct gmio_amf_metadata* ptr_metadata);
/*! Pointer on a function that retrieves the i-th metadata assigned to a
* mesh volume */
void (*func_get_object_mesh_volume_metadata)(
const void* cookie,
const struct gmio_amf_object_mesh_element_index* volume_index,
uint32_t metadata_index,
struct gmio_amf_metadata* ptr_metadata);
};
#endif /* GMIO_AMF_DOCUMENT_H */

88
src/gmio_amf/amf_error.h Normal file
View File

@ -0,0 +1,88 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file amf_error.h
* List of errors specific to AMF I/O functions
*
* \addtogroup gmio_amf
* @{
*/
#ifndef GMIO_AMF_ERROR_H
#define GMIO_AMF_ERROR_H
/*! \c GMIO_AMF_ERROR_TAG
* Byte-mask to tag(identify) AMF-specific error codes */
enum { GMIO_AMF_ERROR_TAG = 0x12000000 };
/*! This enum defines the specific error codes reported by AMF read/write
* functions */
enum gmio_amf_error
{
/*! The input gmio_amf_document is \c NULL */
GMIO_AMF_ERROR_NULL_DOCUMENT = GMIO_AMF_ERROR_TAG + 0x01,
/*! Function pointer gmio_amf_document::func_get_document_element
* is \c NULL */
GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT,
/*! Function pointer gmio_amf_document::func_get_constellation_instance
* is \c NULL */
GMIO_AMF_ERROR_NULL_FUNC_GET_CONSTELLATION_INSTANCE,
/*! Function pointer gmio_amf_document::func_get_object_mesh is \c NULL */
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH,
/*! Function pointer gmio_amf_document::func_get_object_mesh_element
* is \c NULL */
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_ELEMENT,
/*! Function pointer gmio_amf_document::func_get_object_mesh_volume_triangle
* is \c NULL */
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VOLUME_TRIANGLE,
/*! Function pointer gmio_amf_document::func_get_document_element_metadata
* is \c NULL while some gmio_amf_material::metadata_count > 0 */
GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT_METADATA,
/*! Function pointer gmio_amf_document::func_get_material_composite
* is \c NULL while some gmio_amf_material::composite_count > 0 */
GMIO_AMF_ERROR_NULL_FUNC_GET_MATERIAL_COMPOSITE,
/*! Function pointer gmio_amf_document::func_get_object_mesh_vertex_metadata
* is \c NULL while some gmio_amf_vertex::metadata_count > 0 */
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VERTEX_METADATA,
/*! Function pointer gmio_amf_document::func_get_object_mesh_volume_metadata
* is \c NULL while some gmio_amf_volume::metadata_count > 0 */
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VOLUME_METADATA
};
#endif /* GMIO_AMF_ERROR_H */
/*! @} */

66
src/gmio_amf/amf_global.h Normal file
View File

@ -0,0 +1,66 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file amf_global.h
* Global declarations for the AMF module
*
* \defgroup gmio_amf gmioAMF
* Provides API to handle input/output operations with the AMF file format
*
* In addition, the gmioAMF module has the following advatanges:
* \li The user keeps its own geometry data structures, no conversion needed.
* \li Fixed memory consumption and independant of the geometry size
*
* In this module, the name of all entities(structures, functions, ...) are
* prefixed either with \c gmio_amf
*
* <table>
* <tr>
* <th></th> <th>Functions</th> <th>Structures</th>
* </tr>
* <tr>
* <td>Write</td>
* <td>gmio_amf_write()<br/>
* gmio_amf_write_file()</td>
* <td>gmio_amf_document <br/>
* gmio_amf_write_options</td>
* </tr>
* </table>
*
* \addtogroup gmio_amf
* @{
*/
#ifndef GMIO_AMF_GLOBAL_H
#define GMIO_AMF_GLOBAL_H
#include "../gmio_core/global.h"
#endif /* GMIO_AMF_GLOBAL_H */
/*! @} */

944
src/gmio_amf/amf_io.c Normal file
View File

@ -0,0 +1,944 @@
/****************************************************************************
** 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 "amf_io.h"
#include "amf_error.h"
#include "../gmio_core/error.h"
#include "../gmio_core/internal/error_check.h"
#include "../gmio_core/internal/float_format_utils.h"
#include "../gmio_core/internal/helper_memblock.h"
#include "../gmio_core/internal/helper_stream.h"
#include "../gmio_core/internal/helper_task_iface.h"
#include "../gmio_core/internal/ostringstream.h"
#include <stddef.h>
#include <zlib.h>
/* Writing(output) context */
struct gmio_amf_wcontext
{
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;
intmax_t task_progress_max;
struct gmio_ostringstream_format_float f64_format;
int error;
/* zlib specific */
struct gmio_memblock z_memblock;
struct z_stream_s z_stream;
int z_flush;
};
GMIO_INLINE bool gmio_amf_wcontext_set_error(
struct gmio_amf_wcontext* context, int error)
{
context->error = error;
return gmio_no_error(error);
}
GMIO_INLINE void gmio_amf_wcontext_incr_task_progress(
struct gmio_amf_wcontext* context)
{
++(context->task_progress_current);
}
/* Writes double value or its formula (if any) to stream */
static void gmio_amf_write_double(
struct gmio_amf_wcontext* context,
double value,
const char* value_formula)
{
struct gmio_ostringstream* sstream = context->sstream;
if (value_formula == NULL || *value_formula == '\0')
gmio_ostringstream_write_f64(sstream, value, &context->f64_format);
else
gmio_ostringstream_write_str(sstream, value_formula);
}
/* Writes gmio_amf_color component to stream */
static void gmio_amf_write_color_component(
struct gmio_amf_wcontext* context,
double value,
const char* value_formula)
{
struct gmio_ostringstream* sstream = context->sstream;
if (value_formula == NULL || *value_formula == '\0') {
gmio_ostringstream_write_f64(sstream, value, &context->f64_format);
}
else {
gmio_ostringstream_write_xmlcdata_open(sstream);
gmio_ostringstream_write_str(sstream, value_formula);
gmio_ostringstream_write_xmlcdata_close(sstream);
}
}
/* Writes gmio_amf_color to stream */
static void gmio_amf_write_color(
struct gmio_amf_wcontext* context,
const struct gmio_amf_color* color)
{
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>");
gmio_amf_write_color_component(context, color->g, color->g_formula);
gmio_ostringstream_write_chararray(sstream, "</g><b>");
gmio_amf_write_color_component(context, color->b, color->b_formula);
gmio_ostringstream_write_chararray(sstream, "</b><a>");
gmio_amf_write_color_component(context, color->a, color->a_formula);
gmio_ostringstream_write_chararray(sstream, "</a></color>\n");
}
/* Writes gmio_amf_metadata to stream */
static void gmio_amf_write_metadata(
struct gmio_ostringstream* sstream,
const struct gmio_amf_metadata* metadata)
{
gmio_ostringstream_write_chararray(sstream, "<metadata");
gmio_ostringstream_write_xmlattr_str(sstream, "type", metadata->type);
gmio_ostringstream_write_char(sstream, '>');
gmio_ostringstream_write_str(sstream, metadata->data);
gmio_ostringstream_write_chararray(sstream, "</metadata>\n");
}
/* Writes <amf ...> to stream */
static void gmio_amf_write_amf_begin(
struct gmio_ostringstream* sstream,
const struct gmio_amf_document* doc)
{
gmio_ostringstream_write_chararray(
sstream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
gmio_ostringstream_write_chararray(sstream, "<amf");
if (doc->unit != GMIO_AMF_UNIT_UNKNOWN) {
const char* unit_str = "";
switch (doc->unit) {
case GMIO_AMF_UNIT_MILLIMETER:
unit_str = "millimeter"; break;
case GMIO_AMF_UNIT_INCH:
unit_str = "inch"; break;
case GMIO_AMF_UNIT_FEET:
unit_str = "feet"; break;
case GMIO_AMF_UNIT_METER:
unit_str = "meter"; break;
case GMIO_AMF_UNIT_MICRON:
unit_str = "micron"; break;
case GMIO_AMF_UNIT_UNKNOWN: /* Silent compiler warning */
break;
}
gmio_ostringstream_write_xmlattr_str(sstream, "unit", unit_str);
}
gmio_ostringstream_write_xmlattr_str(sstream, "version", "1.2");
gmio_ostringstream_write_chararray(sstream, ">\n");
}
/* Writes document metadata to stream */
static bool gmio_amf_write_root_metadata(
struct gmio_amf_wcontext* context)
{
const struct gmio_amf_document* doc = context->document;
struct gmio_amf_metadata metadata = {0};
uint32_t imeta;
for (imeta = 0; imeta < doc->metadata_count; ++imeta) {
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_METADATA, imeta, &metadata);
gmio_amf_write_metadata(context->sstream, &metadata);
gmio_amf_wcontext_incr_task_progress(context);
}
return gmio_no_error(context->error);
}
/* Writes document materials to stream */
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_amf_material material = {0};
uint32_t imat;
for (imat = 0; imat < doc->material_count; ++imat) {
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL, imat, &material);
gmio_ostringstream_write_chararray(sstream, "<material");
gmio_ostringstream_write_xmlattr_u32(sstream, "id", material.id);
gmio_ostringstream_write_char(sstream, '>');
/* Write material <metadata> elements */
if (material.metadata_count > 0) {
uint32_t imeta;
struct gmio_amf_metadata metadata = {0};
/* Check function pointer is defined */
if (doc->func_get_document_element_metadata == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT_METADATA);
}
for (imeta = 0; imeta < material.metadata_count; ++imeta) {
doc->func_get_document_element_metadata(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL,
imat,
imeta,
&metadata);
gmio_amf_write_metadata(sstream, &metadata);
}
}
/* Write material <color> element */
gmio_amf_write_color(context, &material.color);
/* Write material <composite> elements */
if (material.composite_count > 0) {
struct gmio_amf_composite composite = {0};
uint32_t icomp;
/* Check function pointer is defined */
if (doc->func_get_material_composite == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_MATERIAL_COMPOSITE);
}
for (icomp = 0; icomp < material.composite_count; ++icomp) {
doc->func_get_material_composite(
doc->cookie, imat, icomp, &composite);
gmio_ostringstream_write_chararray(sstream, "<composite");
gmio_ostringstream_write_xmlattr_u32(
sstream, "materialid", composite.materialid);
gmio_ostringstream_write_char(sstream, '>');
gmio_ostringstream_write_xmlcdata_open(sstream);
gmio_amf_write_double(
context, composite.value, composite.value_formula);
gmio_ostringstream_write_xmlcdata_close(sstream);
gmio_ostringstream_write_chararray(sstream, "</composite>\n");
}
}
gmio_ostringstream_write_chararray(sstream, "</material>\n");
gmio_amf_wcontext_incr_task_progress(context);
}
return gmio_no_error(context->error);
}
/* Write gmio_amf_texmap to stream */
static void gmio_amf_write_texmap(
struct gmio_ostringstream* sstream,
const struct gmio_amf_texmap* texmap)
{
/* Write triangle <texmap ...> element */
gmio_ostringstream_write_chararray(sstream, "<texmap");
gmio_ostringstream_write_xmlattr_u32(sstream, "rtexid", texmap->rtexid);
gmio_ostringstream_write_xmlattr_u32(sstream, "gtexid", texmap->gtexid);
gmio_ostringstream_write_xmlattr_u32(sstream, "btexid", texmap->btexid);
gmio_ostringstream_write_xmlattr_u32(sstream, "atexid", texmap->atexid);
gmio_ostringstream_write_char(sstream, '>');
/* Write triangle <utex> elements */
gmio_ostringstream_write_xmlelt_f64(sstream, "utex1", texmap->utex.x);
gmio_ostringstream_write_xmlelt_f64(sstream, "utex2", texmap->utex.y);
gmio_ostringstream_write_xmlelt_f64(sstream, "utex3", texmap->utex.z);
/* Write triangle <vtex> elements */
gmio_ostringstream_write_xmlelt_f64(sstream, "vtex1", texmap->vtex.x);
gmio_ostringstream_write_xmlelt_f64(sstream, "vtex2", texmap->vtex.y);
gmio_ostringstream_write_xmlelt_f64(sstream, "vtex3", texmap->vtex.z);
/* Write triangle <wtex> elements */
if (texmap->has_wtex) {
gmio_ostringstream_write_xmlelt_f64(sstream, "wtex1", texmap->wtex.x);
gmio_ostringstream_write_xmlelt_f64(sstream, "wtex2", texmap->wtex.y);
gmio_ostringstream_write_xmlelt_f64(sstream, "wtex3", texmap->wtex.z);
}
gmio_ostringstream_write_chararray(sstream, "</texmap>\n");
}
/* Writes gmio_amf_mesh to stream */
static bool gmio_amf_write_mesh(
struct gmio_amf_wcontext* context,
const struct gmio_amf_mesh* 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_amf_object_mesh_element_index mesh_elt_index =
*base_mesh_element_index;
const struct gmio_ostringstream_format_float* f64_format =
&context->f64_format;
struct gmio_amf_vertex vertex = {0};
uint32_t ivert;
/* Write mesh <vertices> element */
gmio_ostringstream_write_chararray(sstream, "<mesh>\n<vertices>");
for (ivert = 0; ivert < mesh->vertex_count; ++ivert) {
mesh_elt_index.value = ivert;
doc->func_get_object_mesh_element(
doc->cookie,
GMIO_AMF_MESH_ELEMENT_VERTEX, &mesh_elt_index, &vertex);
/* Write <coordinates> element */
gmio_ostringstream_write_chararray(sstream, "<vertex><coordinates>");
gmio_ostringstream_write_chararray(sstream, "<x>");
gmio_ostringstream_write_f64(sstream, vertex.coords.x, f64_format);
gmio_ostringstream_write_chararray(sstream, "</x><y>");
gmio_ostringstream_write_f64(sstream, vertex.coords.y, f64_format);
gmio_ostringstream_write_chararray(sstream, "</y><z>");
gmio_ostringstream_write_f64(sstream, vertex.coords.z, f64_format);
gmio_ostringstream_write_chararray(sstream, "</z></coordinates>");
/* Write <color> element */
if (vertex.has_color)
gmio_amf_write_color(context, &vertex.color);
/* Write <normal> element */
if (vertex.has_normal) {
gmio_ostringstream_write_chararray(sstream, "<normal><nx>");
gmio_ostringstream_write_f64(sstream, vertex.normal.x, f64_format);
gmio_ostringstream_write_chararray(sstream, "</nx><ny>");
gmio_ostringstream_write_f64(sstream, vertex.normal.y, f64_format);
gmio_ostringstream_write_chararray(sstream, "</ny><nz>");
gmio_ostringstream_write_f64(sstream, vertex.normal.z, f64_format);
gmio_ostringstream_write_chararray(sstream, "</nz></normal>\n");
}
/* Write <metadata> elements */
if (vertex.metadata_count > 0) {
struct gmio_amf_metadata metadata = {0};
uint32_t imeta;
/* Check function pointer */
if (doc->func_get_object_mesh_vertex_metadata == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VERTEX_METADATA);
}
for (imeta = 0; imeta < vertex.metadata_count; ++imeta) {
doc->func_get_object_mesh_vertex_metadata(
doc->cookie, &mesh_elt_index, imeta, &metadata);
gmio_amf_write_metadata(sstream, &metadata);
}
}
gmio_ostringstream_write_chararray(sstream, "</vertex>\n");
gmio_amf_wcontext_incr_task_progress(context);
if (gmio_error(context->error))
return false;
}
/* Write mesh vertices <edge> elements */
if (mesh->edge_count > 0) {
struct gmio_amf_edge edge = {0};
uint32_t iedge;
for (iedge = 0; iedge < mesh->edge_count; ++iedge) {
mesh_elt_index.value = iedge;
doc->func_get_object_mesh_element(
doc->cookie,
GMIO_AMF_MESH_ELEMENT_EDGE, &mesh_elt_index, &edge);
gmio_ostringstream_write_chararray(sstream, "<edge><v1>");
gmio_ostringstream_write_u32(sstream, edge.v1);
gmio_ostringstream_write_chararray(sstream, "</v1><dx1>");
gmio_ostringstream_write_f64(sstream, edge.d1.x, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dx1><dy1>");
gmio_ostringstream_write_f64(sstream, edge.d1.y, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dy1><dz1>");
gmio_ostringstream_write_f64(sstream, edge.d1.z, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dz1><v2>");
gmio_ostringstream_write_u32(sstream, edge.v2);
gmio_ostringstream_write_chararray(sstream, "</v2><dx2>");
gmio_ostringstream_write_f64(sstream, edge.d2.x, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dx2><dy2>");
gmio_ostringstream_write_f64(sstream, edge.d2.y, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dy2><dz2>");
gmio_ostringstream_write_f64(sstream, edge.d2.z, f64_format);
gmio_ostringstream_write_chararray(sstream, "</dz2></edge>\n");
gmio_amf_wcontext_incr_task_progress(context);
if (gmio_error(context->error))
return false;
}
}
gmio_ostringstream_write_chararray(sstream, "</vertices>\n");
/* Write mesh <volume> elements */
if (mesh->volume_count > 0) {
struct gmio_amf_volume volume = {0};
uint32_t ivol;
for (ivol = 0; ivol < mesh->volume_count; ++ivol) {
const char* str_volume_type = "";
mesh_elt_index.value = ivol;
doc->func_get_object_mesh_element(
doc->cookie,
GMIO_AMF_MESH_ELEMENT_VOLUME, &mesh_elt_index, &volume);
/* Write <volume ...> element begin */
gmio_ostringstream_write_chararray(sstream, "<volume");
gmio_ostringstream_write_xmlattr_u32(
sstream, "materialid", volume.materialid);
switch (volume.type) {
case GMIO_AMF_VOLUME_TYPE_OBJECT:
str_volume_type = "object"; break;
case GMIO_AMF_VOLUME_TYPE_SUPPORT:
str_volume_type = "support"; break;
}
gmio_ostringstream_write_xmlattr_str(sstream, "type", str_volume_type);
gmio_ostringstream_write_char(sstream, '>');
/* Write volume <metadata> elements */
if (volume.metadata_count > 0) {
struct gmio_amf_metadata metadata = {0};
uint32_t imeta;
/* Check function pointer */
if (doc->func_get_object_mesh_volume_metadata == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VOLUME_METADATA);
}
for (imeta = 0; imeta < volume.metadata_count; ++imeta) {
doc->func_get_object_mesh_volume_metadata(
doc->cookie, &mesh_elt_index, imeta, &metadata);
gmio_amf_write_metadata(sstream, &metadata);
}
}
/* Write volume <color> element */
if (volume.has_color)
gmio_amf_write_color(context, &volume.color);
/* Write <triangle> elements */
if (volume.triangle_count > 0) {
struct gmio_amf_triangle triangle = {0};
uint32_t itri;
for (itri = 0; itri < volume.triangle_count; ++itri) {
doc->func_get_object_mesh_volume_triangle(
doc->cookie, &mesh_elt_index, itri, &triangle);
gmio_ostringstream_write_chararray(sstream, "<triangle>");
/* Write triangle <color> element */
if (triangle.has_color)
gmio_amf_write_color(context, &triangle.color);
/* Write triangle <v1> <v2> <v3> elements */
gmio_ostringstream_write_chararray(sstream, "<v1>");
gmio_ostringstream_write_u32(sstream, triangle.v1);
gmio_ostringstream_write_chararray(sstream, "</v1><v2>");
gmio_ostringstream_write_u32(sstream, triangle.v2);
gmio_ostringstream_write_chararray(sstream, "</v2><v3>");
gmio_ostringstream_write_u32(sstream, triangle.v3);
gmio_ostringstream_write_chararray(sstream, "</v3>");
/* Write triangle <texmap> element */
if (triangle.has_texmap)
gmio_amf_write_texmap(sstream, &triangle.texmap);
gmio_ostringstream_write_chararray(sstream, "</triangle>\n");
gmio_amf_wcontext_incr_task_progress(context);
if (gmio_error(context->error))
return false;
}
}
gmio_ostringstream_write_chararray(sstream, "</volume>\n");
}
}
gmio_ostringstream_write_chararray(sstream, "</mesh>\n");
return gmio_no_error(context->error);
}
/* Writes document objects to stream */
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_amf_object object = {0};
uint32_t iobj;
for (iobj = 0; iobj < doc->object_count; ++iobj) {
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_OBJECT, iobj, &object);
/* Open object element */
gmio_ostringstream_write_chararray(sstream, "<object");
gmio_ostringstream_write_xmlattr_u32(sstream, "id", object.id);
gmio_ostringstream_write_char(sstream, '>');
/* Write metadata elements */
if (object.metadata_count > 0) {
struct gmio_amf_metadata metadata = {0};
uint32_t imeta;
/* Check function pointer */
if (doc->func_get_document_element_metadata == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT_METADATA);
}
for (imeta = 0; imeta < object.metadata_count; ++imeta) {
doc->func_get_document_element_metadata(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_OBJECT,
iobj,
imeta,
&metadata);
gmio_amf_write_metadata(sstream, &metadata);
}
}
/* Write color element if any */
if (object.has_color)
gmio_amf_write_color(context, &object.color);
/* Write mesh elements */
if (object.mesh_count > 0) {
struct gmio_amf_mesh mesh = {0};
uint32_t imesh;
for (imesh = 0; imesh < object.mesh_count; ++imesh) {
struct gmio_amf_object_mesh_element_index base_mesh_elt_index;
doc->func_get_object_mesh(doc->cookie, iobj, imesh, &mesh);
base_mesh_elt_index.object_index = iobj;
base_mesh_elt_index.mesh_index = imesh;
base_mesh_elt_index.value = 0;
gmio_amf_write_mesh(context, &mesh, &base_mesh_elt_index);
if (gmio_error(context->error))
return false;
}
}
/* Close object element */
gmio_ostringstream_write_chararray(sstream, "</object>\n");
}
return gmio_no_error(context->error);
}
/* Writes document objects to stream */
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_amf_texture texture = {0};
uint32_t itex;
for (itex = 0; itex < doc->texture_count; ++itex) {
const char* str_texture_type = "";
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_TEXTURE, itex, &texture);
gmio_ostringstream_write_chararray(sstream, "<texture");
gmio_ostringstream_write_xmlattr_u32(sstream, "id", texture.id);
gmio_ostringstream_write_xmlattr_u32(sstream, "width", texture.width);
gmio_ostringstream_write_xmlattr_u32(sstream, "height", texture.height);
gmio_ostringstream_write_xmlattr_u32(sstream, "depth", texture.depth);
gmio_ostringstream_write_xmlattr_str(
sstream, "tiled", texture.tiled ? "true" : "false");
switch (texture.type) {
case GMIO_AMF_TEXTURE_TYPE_GRAYSCALE:
str_texture_type = "grayscale"; break;
}
gmio_ostringstream_write_xmlattr_str(sstream, "type", str_texture_type);
gmio_ostringstream_write_char(sstream, '>');
gmio_ostringstream_write_base64(
sstream,
texture.binary_data.ptr,
texture.binary_data.size);
gmio_ostringstream_write_chararray(sstream, "</texture>\n");
gmio_amf_wcontext_incr_task_progress(context);
if (gmio_error(context->error))
return false;
}
return gmio_no_error(context->error);
}
/* Writes document constellations to stream */
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_amf_constellation constellation = {0};
uint32_t icons;
for (icons = 0; icons < doc->constellation_count; ++icons) {
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION, icons, &constellation);
gmio_ostringstream_write_chararray(sstream, "<constellation");
gmio_ostringstream_write_xmlattr_u32(sstream, "id", constellation.id);
gmio_ostringstream_write_char(sstream, '>');
/* Write constellation <metadata> elements */
if (constellation.metadata_count > 0) {
struct gmio_amf_metadata metadata = {0};
uint32_t imeta;
/* Check function pointer */
if (doc->func_get_document_element_metadata == NULL) {
return gmio_amf_wcontext_set_error(
context,
GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT_METADATA);
}
for (imeta = 0; imeta < constellation.metadata_count; ++imeta) {
doc->func_get_document_element_metadata(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION,
icons,
imeta,
&metadata);
gmio_amf_write_metadata(sstream, &metadata);
}
}
/* Write constellation <instance> elements */
if (constellation.instance_count > 0) {
struct gmio_amf_instance instance = {0};
uint32_t iinst;
for (iinst = 0; iinst < constellation.instance_count; ++iinst) {
doc->func_get_constellation_instance(
doc->cookie, icons, iinst, &instance);
gmio_ostringstream_write_chararray(sstream, "<instance");
gmio_ostringstream_write_xmlattr_u32(
sstream, "objectid", instance.objectid);
gmio_ostringstream_write_char(sstream, '>');
gmio_ostringstream_write_xmlelt_f64(
sstream, "deltax", instance.delta.x);
gmio_ostringstream_write_xmlelt_f64(
sstream, "deltay", instance.delta.y);
gmio_ostringstream_write_xmlelt_f64(
sstream, "deltaz", instance.delta.z);
gmio_ostringstream_write_xmlelt_f64(
sstream, "rx", instance.rot.x);
gmio_ostringstream_write_xmlelt_f64(
sstream, "ry", instance.rot.y);
gmio_ostringstream_write_xmlelt_f64(
sstream, "rz", instance.rot.z);
gmio_ostringstream_write_chararray(sstream, "</instance>\n");
gmio_amf_wcontext_incr_task_progress(context);
if (gmio_error(context->error))
return false;
}
}
gmio_ostringstream_write_chararray(sstream, "</constellation>\n");
}
return gmio_no_error(context->error);
}
/* Returns true if internal document data are roughly accessible */
static bool gmio_amf_check_error(
int* error, const struct gmio_amf_document* doc)
{
if (doc == NULL) {
*error = GMIO_AMF_ERROR_NULL_DOCUMENT;
}
else if (doc->func_get_document_element == NULL) {
*error = GMIO_AMF_ERROR_NULL_FUNC_GET_DOCUMENT_ELEMENT;
}
else if (doc->constellation_count > 0
&& doc->func_get_constellation_instance == NULL)
{
*error = GMIO_AMF_ERROR_NULL_FUNC_GET_CONSTELLATION_INSTANCE;
}
else if (doc->func_get_object_mesh == NULL) {
*error = GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH;
}
else if (doc->func_get_object_mesh_element == NULL) {
*error = GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_ELEMENT;
}
else if (doc->func_get_object_mesh_volume_triangle == NULL) {
*error = GMIO_AMF_ERROR_NULL_FUNC_GET_OBJECT_MESH_VOLUME_TRIANGLE;
}
return gmio_no_error(*error);
}
/* Converts zlib error to gmio "zlib-specific" error */
static int zlib_error_to_gmio_error(int error)
{
switch (error) {
case Z_OK: return GMIO_ERROR_OK;
case Z_ERRNO: return GMIO_ERROR_ZLIB_ERRNO;
case Z_STREAM_ERROR: return GMIO_ERROR_ZLIB_STREAM;
case Z_DATA_ERROR: return GMIO_ERROR_ZLIB_DATA;
case Z_MEM_ERROR: return GMIO_ERROR_ZLIB_MEM;
case Z_BUF_ERROR: return GMIO_ERROR_ZLIB_BUF;
case Z_VERSION_ERROR: return GMIO_ERROR_ZLIB_VERSION;
}
return GMIO_ERROR_UNKNOWN;
}
/* Helper for gmio_amf_ostringstream_write() to write zlib compressed data */
static size_t gmio_amf_ostringstream_write_zlib(
struct gmio_amf_wcontext* context,
struct gmio_stream* stream,
const char* ptr,
size_t len)
{
struct gmio_memblock* z_mblock = &context->z_memblock;
struct z_stream_s* z_stream = &context->z_stream;
size_t total_written_len = 0;
int z_retcode = Z_OK;
z_stream->next_in = (z_const Bytef*)ptr;
z_stream->avail_in = len; /* TODO: use better cast */
/* Run zlib deflate() on input until output buffer not full
* Finish compression when zflush == Z_FINISH */
do {
z_stream->next_out = z_mblock->ptr;
z_stream->avail_out = z_mblock->size;
z_retcode = deflate(z_stream, context->z_flush);
/* Check state not clobbered */
if (z_retcode == Z_STREAM_ERROR) {
context->error = zlib_error_to_gmio_error(z_retcode);
return total_written_len;
}
/* Write zlib output to stream */
{
const size_t z_out_len =
z_mblock->size - z_stream->avail_out;
const size_t written_len =
gmio_stream_write_bytes(stream, z_mblock->ptr, z_out_len);
total_written_len += written_len;
if (written_len != z_out_len || gmio_stream_error(stream)) {
context->error = GMIO_ERROR_STREAM;
return total_written_len;
}
}
} while (z_stream->avail_out == 0);
/* Check all input was used */
if (z_stream->avail_in != 0) {
/* TODO: set more precise error */
context->error = GMIO_ERROR_UNKNOWN;
return total_written_len;
}
/* Check stream is complete */
if (context->z_flush == Z_FINISH && z_retcode != Z_STREAM_END) {
/* TODO: set more precise error */
context->error = GMIO_ERROR_UNKNOWN;
return total_written_len;
}
return total_written_len;
/* zlib official "howto" from http://zlib.net/zlib_how.html */
#if 0
/* compress until end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
deflateEnd(&strm);
return Z_OK;
#endif
}
/* Function called through gmio_ostringstream::func_stream_write */
static size_t gmio_amf_ostringstream_write(
void* cookie, struct gmio_stream* stream, const char* ptr, size_t len)
{
struct gmio_amf_wcontext* context = (struct gmio_amf_wcontext*)cookie;
size_t len_written = 0;
if (gmio_no_error(context->error)) {
if (context->options->compress) {
len_written =
gmio_amf_ostringstream_write_zlib(context, stream, ptr, len);
}
else {
len_written = gmio_stream_write_bytes(stream, ptr, len);
if (len_written != len)
context->error = GMIO_ERROR_STREAM;
}
if (gmio_no_error(context->error)) {
gmio_task_iface_handle_progress(
context->task_iface,
context->task_progress_current,
context->task_progress_max);
if (gmio_task_iface_is_stop_requested(context->task_iface))
context->error = GMIO_ERROR_TASK_STOPPED;
}
}
return len_written;
}
/* Returns computation upper limit of the task progress */
static intmax_t gmio_amf_task_progress_max(const struct gmio_amf_document* doc)
{
intmax_t progress_max = 0;
progress_max += doc->metadata_count;
progress_max += doc->material_count;
progress_max += doc->texture_count;
/* Add total object(vertex_count + edge_count + triangle_count) */
{
struct gmio_amf_object object = {0};
uint32_t iobj;
for (iobj = 0; iobj < doc->object_count; ++iobj) {
struct gmio_amf_mesh mesh = {0};
uint32_t imesh;
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_OBJECT, iobj, &object);
for (imesh = 0; imesh < object.mesh_count; ++imesh) {
doc->func_get_object_mesh(doc->cookie, iobj, imesh, &mesh);
progress_max += mesh.vertex_count;
progress_max += mesh.edge_count;
{
struct gmio_amf_object_mesh_element_index mesh_elt_index;
uint32_t ivol;
mesh_elt_index.object_index = iobj;
mesh_elt_index.mesh_index = imesh;
mesh_elt_index.value = 0;
for (ivol = 0; ivol < mesh.volume_count; ++ivol) {
struct gmio_amf_volume volume = {0};
mesh_elt_index.value = ivol;
doc->func_get_object_mesh_element(
doc->cookie,
GMIO_AMF_MESH_ELEMENT_VOLUME,
&mesh_elt_index,
&volume);
progress_max += volume.triangle_count;
}
}
}
}
}
/* Add total constellation(instance_count) */
{
struct gmio_amf_constellation constellation = {0};
uint32_t icons;
for (icons = 0; icons < doc->constellation_count; ++icons) {
doc->func_get_document_element(
doc->cookie,
GMIO_AMF_DOCUMENT_ELEMENT_CONSTELLATION,
icons,
&constellation);
progress_max += constellation.instance_count;
}
}
return progress_max;
}
int gmio_amf_write(
struct gmio_stream* stream,
const struct gmio_amf_document* doc,
const struct gmio_amf_write_options* opts)
{
/* Constants */
static const struct gmio_amf_write_options default_write_opts = {0};
struct gmio_memblock_helper mblock_helper =
gmio_memblock_helper(opts != NULL ? &opts->stream_memblock : NULL);
const struct gmio_memblock* memblock = &mblock_helper.memblock;
/* Variables */
struct gmio_amf_wcontext context = {0};
struct gmio_ostringstream sstream =
gmio_ostringstream(
*stream, gmio_string(memblock->ptr, 0, memblock->size));
opts = opts != NULL ? opts : &default_write_opts;
/* Check validity of input parameters */
context.error = GMIO_ERROR_OK;
/* TODO: check stream function pointers */
if (!gmio_check_memblock(&context.error, memblock))
goto label_end;
if (!gmio_amf_check_error(&context.error, doc))
goto label_end;
/* Initialize writing context */
{
const struct gmio_string_16 f64_stdio_format =
gmio_to_stdio_float_format(
opts->float64_format, opts->float64_prec);
context.options = opts;
context.sstream = &sstream;
context.document = doc;
context.task_iface = &opts->task_iface;
context.task_progress_current = 0;
if (context.task_iface->func_handle_progress != NULL)
context.task_progress_max += gmio_amf_task_progress_max(doc);
context.f64_format.printf_format = f64_stdio_format.array;
context.f64_format.text_format = opts->float64_format;
context.f64_format.precision =
opts->float64_prec != 0 ? opts->float64_prec : 16;
/* Initialize internal zlib stream for compression */
if (opts->compress) {
const struct gmio_zlib_compress_options* z_opts =
&opts->z_compress_options;
const size_t mblock_halfsize = memblock->size / 2;
int z_init_error = Z_OK;
context.sstream->strbuff.capacity = mblock_halfsize;
context.z_memblock =
gmio_memblock(
(uint8_t*)memblock->ptr + mblock_halfsize,
mblock_halfsize,
NULL);
z_init_error =
deflateInit2(
&context.z_stream,
z_opts->level,
Z_DEFLATED, /* Method */
15, /* Window bits(default value) */
z_opts->memory_usage,
z_opts->strategy);
if (z_init_error != Z_OK) {
context.error = zlib_error_to_gmio_error(z_init_error);
goto label_end;
}
context.z_flush = Z_NO_FLUSH;
}
}
sstream.cookie = &context;
sstream.func_stream_write = &gmio_amf_ostringstream_write;
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);
label_end:
if (opts->compress)
deflateEnd(&context.z_stream);
gmio_memblock_helper_release(&mblock_helper);
return context.error;
}
int gmio_amf_write_file(
const char* filepath,
const struct gmio_amf_document* doc,
const struct gmio_amf_write_options* opts)
{
const bool compress = opts != NULL ? opts->compress : false;
FILE* file = fopen(filepath, compress ? "wb" : "w");
if (file != NULL) {
struct gmio_stream stream = gmio_stream_stdio(file);
const int error = gmio_amf_write(&stream, doc, opts);
fclose(file);
return error;
}
return GMIO_ERROR_STDIO;
}

85
src/gmio_amf/amf_io.h Normal file
View File

@ -0,0 +1,85 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file amf_io.h
* AMF read/write functions
*
* \addtogroup gmio_amf
* @{
*/
#ifndef GMIO_AMF_IO_H
#define GMIO_AMF_IO_H
#include "amf_global.h"
#include "amf_document.h"
#include "amf_io_options.h"
#include "../gmio_core/stream.h"
GMIO_C_LINKAGE_BEGIN
/*! Writes AMF document to stream
*
* \pre <tt> stream != NULL </tt>
* \pre <tt> doc != NULL </tt>
*
* \p options may be \c NULL in this case default values are used
*
* \return Error code (see gmio_core/error.h and amf_error.h)
*
* \sa gmio_amf_write_file()
*/
GMIO_API int gmio_amf_write(
struct gmio_stream* stream,
const struct gmio_amf_document* doc,
const struct gmio_amf_write_options* opts);
/*! Writes AMF document to stream
*
* This is just a facility function over gmio_amf_write(). The internal stream
* object is created to read file at \p filepath
*
* \pre <tt> filepath != \c NULL </tt>\n
* The file is opened with \c fopen() so \p filepath shall follow the file
* name specifications of the running environment
* \pre <tt> doc != NULL </tt>
*
* \return Error code (see gmio_core/error.h and amf_error.h)
*
* \sa gmio_amf_write(), gmio_stream_stdio(FILE*)
*/
GMIO_API int gmio_amf_write_file(
const char* filepath,
const struct gmio_amf_document* doc,
const struct gmio_amf_write_options* opts);
GMIO_C_LINKAGE_END
#endif /* GMIO_AMF_IO_H */
/*! @} */

View File

@ -0,0 +1,136 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file amf_io_options.h
* Options for AMF read/write functions
*
* \addtogroup gmio_amf
* @{
*/
#ifndef GMIO_AMF_IO_OPTIONS_H
#define GMIO_AMF_IO_OPTIONS_H
#include "amf_global.h"
#include "../gmio_core/memblock.h"
#include "../gmio_core/task_iface.h"
#include "../gmio_core/text_format.h"
/*! zlib compression level, specific values */
enum gmio_zlib_compress_level
{
GMIO_ZLIB_COMPRESS_LEVEL_NONE = -1, /*! Maps to Z_NO_COMPRESSION */
GMIO_ZLIB_COMPRESS_LEVEL_DEFAULT = 0, /*! Maps to Z_DEFAULT_COMPRESSION */
GMIO_ZLIB_COMPRESS_LEVEL_BEST_SPEED = 1, /*! Maps to Z_BEST_SPEED */
GMIO_ZLIB_COMPRESS_LEVEL_BEST_SIZE = 9 /*! Maps to Z_BEST_COMPRESSION */
};
/*! zlib compression strategy */
enum gmio_zlib_compress_strategy
{
GMIO_ZLIB_COMPRESSION_STRATEGY_DEFAULT = 0,
GMIO_ZLIB_COMPRESSION_STRATEGY_FILTERED = 1,
GMIO_ZLIB_COMPRESSION_STRATEGY_HUFFMAN_ONLY = 2,
GMIO_ZLIB_COMPRESSION_STRATEGY_RLE = 3,
GMIO_ZLIB_COMPRESSION_STRATEGY_FIXED = 4
};
/*! zlib compression options
*
* Initialising gmio_zlib_compress_options with \c {0} (or \c {} in C++) is the
* convenient way to set default values.
*/
struct gmio_zlib_compress_options
{
/*! Compression level
*
* \c 0 : default compression
* \c 1 : best speed
* \c 9 : best compression */
uint8_t level;
/*! Compression strategy
*
* \c 0 : default strategy
* \c 1 : filtered
* \c 9 : best compression */
enum gmio_zlib_compress_strategy strategy;
/*! Specifies how much memory should be allocated for the internal
* compression state
*
* The value must belongs to \c [1..9] or equals to \c 0 which maps to the
* default usage.
*
* \c 1 uses minimum memory but is slow and reduces compression ratio
* \c 9 uses maximum memory for optimal speed
*/
uint8_t memory_usage;
};
/*! Options of function gmio_amf_write()
*
* Initialising gmio_amf_write_options with \c {0} (or \c {} in C++) is the
* convenient way to set default values(passing \c NULL to gmio_amf_write() has
* the same effect).
*/
struct gmio_amf_write_options
{
/*! Used by the stream to bufferize I/O operations
*
* If null, then a temporary memblock is created with the global default
* constructor function
*
* \sa gmio_memblock_isnull()
* \sa gmio_memblock_default() */
struct gmio_memblock stream_memblock;
/*! Optional interface by which the I/O operation can be controlled */
struct gmio_task_iface task_iface;
/*! The format used when writting double values as strings
*
* Defaulted to \c GMIO_FLOAT_TEXT_FORMAT_DECIMAL_LOWERCASE when calling
* gmio_amf_write() with \c options==NULL
*/
enum gmio_float_text_format float64_format;
/*! The maximum number of significant digits when writting double values
*
* Defaulted to \c 16 when calling gmio_amf_write() with \c options==NULL
*/
uint8_t float64_prec;
/* ZIP compression */
bool compress;
struct gmio_zlib_compress_options z_compress_options;
};
#endif /* GMIO_AMF_IO_OPTIONS_H */

View File

@ -0,0 +1,87 @@
/****************************************************************************
** 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.
****************************************************************************/
/*! \file const_string.h
* Declaration of gmio_const_string and utility functions
*
* \addtogroup gmio_core
* @{
*/
#ifndef GMIO_CONST_STRING_H
#define GMIO_CONST_STRING_H
#include "global.h"
#include <stddef.h>
/*! Stores a read-only string of 8-bit chars
*
* For faster lookups, it knowns the length of its contents.
*/
struct gmio_const_string
{
const char* ptr; /*!< Contents */
size_t len; /*!< Size(length) of current contents */
};
/*! Expands to bracket initialization of a gmio_const_string from const char[]
*
* Example:
* \code{.c}
* static const char token[] = "woops";
* struct gmio_const_string token_s = GMIO_CONST_STRING_FROM_ARRAY(token);
* \endcode
*/
#define GMIO_CONST_STRING_FROM_ARRAY(array) { &(array)[0], sizeof(array) - 1 }
/*! Returns an initialized gmio_const_string object */
GMIO_INLINE struct gmio_const_string gmio_const_string(const char* ptr, size_t len);
/*! Returns \c true if \p str has no characters, otherwise returns \c false */
GMIO_INLINE bool gmio_const_string_is_empty(const struct gmio_const_string* str);
/*
* -- Implementation
*/
struct gmio_const_string gmio_const_string(const char* ptr, size_t len)
{
struct gmio_const_string cstr;
cstr.ptr = ptr;
cstr.len = len;
return cstr;
}
bool gmio_const_string_is_empty(const struct gmio_const_string* str)
{
return str->ptr == NULL || str->len == 0;
}
#endif /* GMIO_CONST_STRING_H */

View File

@ -92,8 +92,8 @@
/* GMIO_HAVE_INT64_TYPE */
#if defined(GMIO_HAVE_INT64_T) \
|| defined(GMIO_HAVE_MSVC_INT64) \
|| defined(GMIO_HAVE_LONG_LONG)
|| defined(GMIO_HAVE_MSVC_INT64) \
|| defined(GMIO_HAVE_LONG_LONG)
# define GMIO_HAVE_INT64_TYPE
#endif

View File

@ -0,0 +1,67 @@
/****************************************************************************
** 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 "float_format_utils.h"
#include <stdio.h>
char gmio_float_text_format_to_stdio_specifier(
enum gmio_float_text_format format)
{
switch (format) {
case GMIO_FLOAT_TEXT_FORMAT_DECIMAL_LOWERCASE: return 'f';
case GMIO_FLOAT_TEXT_FORMAT_DECIMAL_UPPERCASE: return 'F';
case GMIO_FLOAT_TEXT_FORMAT_SCIENTIFIC_LOWERCASE: return 'e';
case GMIO_FLOAT_TEXT_FORMAT_SCIENTIFIC_UPPERCASE: return 'E';
case GMIO_FLOAT_TEXT_FORMAT_SHORTEST_LOWERCASE: return 'g';
case GMIO_FLOAT_TEXT_FORMAT_SHORTEST_UPPERCASE: return 'G';
}
/* Default, should not be here */
return GMIO_FLOAT_TEXT_FORMAT_DECIMAL_LOWERCASE;
}
char* gmio_write_stdio_float_format(char* buffer, char specifier, uint8_t prec)
{
int prec_len = 0;
buffer[0] = '%';
buffer[1] = '.';
prec_len = sprintf(buffer + 2, "%u", prec);
buffer[2 + prec_len] = specifier;
return buffer + 3 + prec_len;
}
struct gmio_string_16 gmio_to_stdio_float_format(
enum gmio_float_text_format format, uint8_t prec)
{
struct gmio_string_16 buff = {0};
const char spec = gmio_float_text_format_to_stdio_specifier(format);
gmio_write_stdio_float_format(buff.array, spec, prec);
return buff;
}

View File

@ -0,0 +1,45 @@
/****************************************************************************
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above
** copyright notice, this list of conditions and the following
** disclaimer in the documentation and/or other materials provided
** with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#ifndef GMIO_INTERNAL_FLOAT_FORMAT_UTILS_H
#define GMIO_INTERNAL_FLOAT_FORMAT_UTILS_H
#include "../text_format.h"
char gmio_float_text_format_to_stdio_specifier(
enum gmio_float_text_format format);
char* gmio_write_stdio_float_format(
char* buffer, char specifier, uint8_t prec);
struct gmio_string_16 { char array[16]; };
struct gmio_string_16 gmio_to_stdio_float_format(
enum gmio_float_text_format format, uint8_t prec);
#endif /* GMIO_INTERNAL_FLOAT_FORMAT_UTILS_H */

View File

@ -38,17 +38,20 @@
#include <limits>
inline float gmio_snanf()
{
return std::numeric_limits<float>::signaling_NaN();
}
namespace {
inline float gmio_inff()
{
return std::numeric_limits<float>::infinity();
}
template<typename T> T gmio_snan()
{ return std::numeric_limits<T>::signaling_NaN(); }
float gmio_str2float_googledoubleconversion(const char* num, size_t numlen)
template<typename T> T gmio_inf()
{ return std::numeric_limits<T>::infinity(); }
template<typename T> struct FloatTraits {};
template<> struct FloatTraits<float> { static float zero() { return 0.f; } };
template<> struct FloatTraits<double> { static double zero() { return 0.; } };
template<typename T>
T gmio_generic_str2float_googledoubleconversion(const char* num, size_t numlen)
{
// Important note: implementation adapted from Qt5 source code
// qtbase/src/corelib/tools/qlocale_tools.cpp
@ -74,14 +77,14 @@ float gmio_str2float_googledoubleconversion(const char* num, size_t numlen)
bool ok = false;
int processed = 0;
float f = 0.f;
T f = FloatTraits<T>::zero();
static const int conv_flags =
double_conversion::StringToDoubleConverter::NO_FLAGS;
if (*num == '\0') {
ok = false;
processed = 0;
return 0.f;
return FloatTraits<T>::zero();
}
ok = true;
@ -90,38 +93,38 @@ float gmio_str2float_googledoubleconversion(const char* num, size_t numlen)
// or sscanf, we don't allow "-nan" or "+nan"
if (gmio_ascii_stricmp(num, "nan") == 0) {
processed = 3;
return gmio_snanf();
return gmio_snan<T>();
}
else if ((num[0] == '-' || num[0] == '+')
&& gmio_ascii_stricmp(num + 1, "nan") == 0)
{
processed = 0;
ok = false;
return 0.f;
return FloatTraits<T>::zero();
}
// Infinity values are implementation defined in the sscanf case. In the
// libdouble-conversion case we need infinity as overflow marker
if (gmio_ascii_stricmp(num, "+inf") == 0) {
processed = 4;
return gmio_inff();
return gmio_inf<T>();
} else if (gmio_ascii_stricmp(num, "inf") == 0) {
processed = 3;
return gmio_inff();
return gmio_inf<T>();
} else if (gmio_ascii_stricmp(num, "-inf") == 0) {
processed = 4;
return -gmio_inff();
return -gmio_inf<T>();
}
static const double_conversion::StringToDoubleConverter conv(
conv_flags, 0.0, gmio_snanf(), 0, 0);
conv_flags, 0., gmio_snan<T>(), NULL, NULL);
f = conv.StringToFloat(num, static_cast<int>(numlen), &processed);
if (!gmio_isfinite(f)) {
ok = false;
if (gmio_isnan(f)) {
// Garbage found. We don't accept it and return 0
processed = 0;
return 0.f;
return FloatTraits<T>::zero();
} else {
// Overflow. That's not OK, but we still return infinity
return f;
@ -145,8 +148,9 @@ float gmio_str2float_googledoubleconversion(const char* num, size_t numlen)
return f;
}
int gmio_float2str_googledoubleconversion(
float value,
template<typename T>
int gmio_generic_float2str_googledoubleconversion(
T value,
char *buff,
size_t bufflen,
gmio_float_text_format textformat,
@ -181,4 +185,38 @@ int gmio_float2str_googledoubleconversion(
return result_builder.position();
}
} // Anonymous namespace
float gmio_str2float_googledoubleconversion(const char* num, size_t numlen)
{
return ::gmio_generic_str2float_googledoubleconversion<float>(num, numlen);
}
double gmio_str2double_googledoubleconversion(const char* num, size_t numlen)
{
return ::gmio_generic_str2float_googledoubleconversion<double>(num, numlen);
}
int gmio_float2str_googledoubleconversion(
float value,
char *buff,
size_t bufflen,
gmio_float_text_format textformat,
uint8_t prec)
{
return gmio_generic_float2str_googledoubleconversion<float>(
value, buff, bufflen, textformat, prec);
}
int gmio_double2str_googledoubleconversion(
double value,
char* buff,
size_t bufflen,
enum gmio_float_text_format textformat,
uint8_t prec)
{
return gmio_generic_float2str_googledoubleconversion<double>(
value, buff, bufflen, textformat, prec);
}
#endif /* GMIO_STR2FLOAT_LIB == LIB_GOOGLE_DOUBLE_CONVERSION */

View File

@ -42,12 +42,20 @@
GMIO_C_LINKAGE_BEGIN
float gmio_str2float_googledoubleconversion(const char* num, size_t numlen);
double gmio_str2double_googledoubleconversion(const char* num, size_t numlen);
int gmio_float2str_googledoubleconversion(
float value,
char* buff,
size_t bufflen,
enum gmio_float_text_format textformat,
uint8_t prec);
int gmio_double2str_googledoubleconversion(
double value,
char* buff,
size_t bufflen,
enum gmio_float_text_format textformat,
uint8_t prec);
GMIO_C_LINKAGE_END
#endif /* GMIO_INTERNAL_GOOGLE_DOUBLECONVERSION_H */

View File

@ -0,0 +1,76 @@
/****************************************************************************
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above
** copyright notice, this list of conditions and the following
** disclaimer in the documentation and/or other materials provided
** with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#ifndef GMIO_INTERNAL_ITOA_H
#define GMIO_INTERNAL_ITOA_H
#include "../global.h"
GMIO_INLINE char* gmio_u32toa(uint32_t value, char* str);
GMIO_INLINE char* gmio_i32toa(int32_t value, char* str);
#ifdef GMIO_HAVE_INT64_TYPE
GMIO_INLINE char* gmio_u64toa(uint64_t value, char* str);
GMIO_INLINE char* gmio_i64toa(int64_t value, char* str);
#endif
/*
* Implementation
*/
#include "../../3rdparty/miloyip_itoa/branchlut.h"
char* gmio_u32toa(uint32_t value, char* str)
{
if (value < 10) {
*str++ = '0' + (char)value;
return str;
}
else {
return u32toa_branchlut(value, str);
}
}
char* gmio_i32toa(int32_t value, char* str)
{
return i32toa_branchlut(value, str);
}
#ifdef GMIO_HAVE_INT64_TYPE
char* gmio_u64toa(uint64_t value, char* str)
{
return u64toa_branchlut(value, str);
}
char* gmio_i64toa(int64_t value, char* str)
{
return i64toa_branchlut(value, str);
}
#endif /* GMIO_HAVE_INT64_TYPE */
#endif /* GMIO_INTERNAL_ITOA_H */

View File

@ -0,0 +1,214 @@
/****************************************************************************
** 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 "ostringstream.h"
#include "helper_stream.h"
#include "itoa.h"
#include "min_max.h"
#include "../../3rdparty/base64/b64.h"
#if GMIO_FLOAT2STR_LIB == GMIO_FLOAT2STR_LIB_STD
# include "c99_stdio_compat.h"
#elif GMIO_FLOAT2STR_LIB == GMIO_FLOAT2STR_LIB_DOUBLE_CONVERSION
# include "google_doubleconversion.h"
#endif
#include <string.h>
GMIO_INLINE char* gmio_ostringstream_strbuff_pos(
const struct gmio_ostringstream* sstream)
{
return sstream->strbuff.ptr + sstream->strbuff.len;
}
GMIO_INLINE size_t gmio_string_remaining_capacity(const struct gmio_string* str)
{
return str->capacity - str->len;
}
struct gmio_ostringstream gmio_ostringstream(
const struct gmio_stream stream, const struct gmio_string strbuff)
{
struct gmio_ostringstream sstream = {0};
sstream.stream = stream;
sstream.strbuff = strbuff;
sstream.func_stream_write = gmio_ostringstream_default_func_write;
return sstream;
}
size_t gmio_ostringstream_default_func_write(
void* cookie, struct gmio_stream* stream, const char* ptr, size_t len)
{
GMIO_UNUSED(cookie);
return gmio_stream_write_bytes(stream, ptr, len);
}
void gmio_ostringstream_write_str(
struct gmio_ostringstream *sstream, const char *str)
{
gmio_ostringstream_write_nstr(sstream, str, strlen(str));
}
void gmio_ostringstream_write_nstr(
struct gmio_ostringstream *sstream, const char *str, size_t n)
{
struct gmio_string* strbuff = &sstream->strbuff;
if (n > strbuff->capacity) {
/* No need to bufferize copy */
gmio_ostringstream_flush(sstream);
sstream->func_stream_write(sstream->cookie, &sstream->stream, str, n);
}
else {
/* str fits in sstream->strbuff */
if (n >= gmio_string_remaining_capacity(strbuff))
gmio_ostringstream_flush(sstream);
strncpy(gmio_ostringstream_strbuff_pos(sstream), str, n);
strbuff->len += n;
}
}
void gmio_ostringstream_write_xmlattr_str(
struct gmio_ostringstream *sstream, const char *attr, const char *val)
{
gmio_ostringstream_write_char(sstream, ' ');
gmio_ostringstream_write_str(sstream, attr);
gmio_ostringstream_write_chararray(sstream, "=\"");
gmio_ostringstream_write_str(sstream, val);
gmio_ostringstream_write_char(sstream, '\"');
}
void gmio_ostringstream_write_xmlattr_u32(
struct gmio_ostringstream *sstream, const char *attr, uint32_t val)
{
gmio_ostringstream_write_char(sstream, ' ');
gmio_ostringstream_write_str(sstream, attr);
gmio_ostringstream_write_chararray(sstream, "=\"");
gmio_ostringstream_write_u32(sstream, val);
gmio_ostringstream_write_char(sstream, '\"');
}
void gmio_ostringstream_write_u32(
struct gmio_ostringstream *sstream, uint32_t value)
{
struct gmio_string* buff = &sstream->strbuff;
char* buffpos;
const char* newbuffpos;
if (gmio_string_remaining_capacity(buff) < 10)
gmio_ostringstream_flush(sstream);
buffpos = buff->ptr + buff->len;
newbuffpos = gmio_u32toa(value, buffpos);
buff->len += newbuffpos - buffpos;
}
void gmio_ostringstream_write_i32(
struct gmio_ostringstream *sstream, int32_t value)
{
struct gmio_string* buff = &sstream->strbuff;
char* buffpos;
const char* newbuffpos;
if (gmio_string_remaining_capacity(buff) < 11) /* 10 digits + '-' sign */
gmio_ostringstream_flush(sstream);
buffpos = buff->ptr + buff->len;
newbuffpos = gmio_i32toa(value, buffpos);
buff->len += newbuffpos - buffpos;
}
void gmio_ostringstream_write_xmlelt_f64(
struct gmio_ostringstream *sstream, const char *elt, double val)
{
const size_t elt_strlen = strlen(elt);
gmio_ostringstream_write_char(sstream, '<');
gmio_ostringstream_write_nstr(sstream, elt, elt_strlen);
gmio_ostringstream_write_char(sstream, '>');
gmio_ostringstream_write_f64(sstream, val, NULL);
gmio_ostringstream_write_nstr(sstream, "</", 2);
gmio_ostringstream_write_nstr(sstream, elt, elt_strlen);
gmio_ostringstream_write_char(sstream, '>');
}
void gmio_ostringstream_write_f64(
struct gmio_ostringstream *sstream,
double value,
const struct gmio_ostringstream_format_float *format)
{
static const struct gmio_ostringstream_format_float default_format = {
"%.16g", GMIO_FLOAT_TEXT_FORMAT_SHORTEST_UPPERCASE, 16 };
const struct gmio_ostringstream_format_float* nformat =
format != NULL ? format : &default_format;
struct gmio_string* buff = &sstream->strbuff;
int written_count = 0;
if (buff->capacity - buff->len < 32)
gmio_ostringstream_flush(sstream);
#if GMIO_FLOAT2STR_LIB == GMIO_FLOAT2STR_LIB_STD
written_count = gmio_snprintf(
buff->ptr + buff->len,
buff->capacity - buff->len,
nformat->printf_format,
value);
#elif GMIO_FLOAT2STR_LIB == GMIO_FLOAT2STR_LIB_DOUBLE_CONVERSION
written_count = gmio_double2str_googledoubleconversion(
value,
buff->ptr + buff->len,
buff->capacity - buff->len,
nformat->text_format,
nformat->precision);
#endif
buff->len += written_count;
}
void gmio_ostringstream_write_base64(
struct gmio_ostringstream *sstream,
const unsigned char *input,
size_t len)
{
struct gmio_string* buff = &sstream->strbuff;
size_t pos = 0;
while (pos < len) {
const size_t remaining_len = len - pos;
unsigned char* output;
if (gmio_string_remaining_capacity(buff) < 4)
gmio_ostringstream_flush(sstream);
output = (unsigned char*)(buff->ptr + buff->len);
if (remaining_len >= 3) {
b64_encodeblock(input + pos, output, 3);
}
else {
unsigned char temp_in[3] = {0};
if (remaining_len > 0)
temp_in[0] = *(input + pos);
if (remaining_len > 1)
temp_in[1] = *(input + pos + 1);
b64_encodeblock(temp_in, output, remaining_len);
}
pos += 3;
buff->len += 4;
}
}

View File

@ -0,0 +1,180 @@
/****************************************************************************
** Copyright (c) 2016, Fougue Ltd. <http://www.fougue.pro>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above
** copyright notice, this list of conditions and the following
** disclaimer in the documentation and/or other materials provided
** with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#ifndef GMIO_INTERNAL_OSTRINGSTREAM_H
#define GMIO_INTERNAL_OSTRINGSTREAM_H
#include "../global.h"
#include "../stream.h"
#include "../text_format.h"
#include "string.h"
/*! Output stream that operates on a string
*
* To be used with API below.
*/
struct gmio_ostringstream
{
/*! Stream to iterate over */
struct gmio_stream stream;
/*! Holds contents chunk to write in stream(when full) */
struct gmio_string strbuff;
/*! Data to be passed to callback func_stream_write */
void* cookie;
/*! Pointer on a function called each time next contents chunk has to be
* written */
size_t (*func_stream_write)(
void* cookie, struct gmio_stream* stream, const char* ptr, size_t len);
};
/*! Returns an initialized gmio_ostringstream object */
struct gmio_ostringstream gmio_ostringstream(
const struct gmio_stream stream,
const struct gmio_string strbuff);
/*! Default function for gmio_ostringstream::func_stream_write */
size_t gmio_ostringstream_default_func_write(
void* cookie, struct gmio_stream* stream, const char* ptr, size_t len);
/*! Writes null-terminated C string \p str to ostringstream \p sstream */
void gmio_ostringstream_write_str(
struct gmio_ostringstream* sstream, const char* str);
/*! Writes the first \p n characters from C string \p str to ostringstream
* \p sstream */
void gmio_ostringstream_write_nstr(
struct gmio_ostringstream* sstream, const char* str, size_t n);
/*! Writes the character \p array to ostringstream \p sstream
*
* It is a facility around gmio_ostringstream_write_nstr() for string literals
* and <tt>char[]</tt>
* \code
* const char str[] = "stuff";
* gmio_ostringstream_write_chararray(sstream, "something");
* gmio_ostringstream_write_chararray(sstream, str);
* \endcode
*/
#define gmio_ostringstream_write_chararray(sstream, array) \
gmio_ostringstream_write_nstr((sstream), (array), sizeof(array) - 1)
/*! Writes character \p c to ostringstream \p sstream */
GMIO_INLINE void gmio_ostringstream_write_char(
struct gmio_ostringstream* sstream, char c);
/*! Writes uint32 \p value to ostringstream \p sstream */
void gmio_ostringstream_write_u32(
struct gmio_ostringstream* sstream, uint32_t value);
/*! Writes int32 \p value to ostringstream \p sstream */
void gmio_ostringstream_write_i32(
struct gmio_ostringstream* sstream, int32_t value);
/*! Format specification for float numbers(single or double precision) */
struct gmio_ostringstream_format_float
{
const char* printf_format; /* printf-like format(eg. "%.7f") */
enum gmio_float_text_format text_format;
uint8_t precision;
};
/*! Writes double \p value to ostringstream \p sstream */
void gmio_ostringstream_write_f64(
struct gmio_ostringstream* sstream,
double value,
const struct gmio_ostringstream_format_float* format);
/*! Writes \p input encoded to base64 */
void gmio_ostringstream_write_base64(
struct gmio_ostringstream* sstream,
const unsigned char* input,
size_t len);
/*! Write pending bytes within sstream->strbuff */
GMIO_INLINE void gmio_ostringstream_flush(struct gmio_ostringstream* sstream);
/* XML */
/*! Write XML attribute of name \p attr and value \p val */
void gmio_ostringstream_write_xmlattr_str(
struct gmio_ostringstream* sstream, const char* attr, const char* val);
void gmio_ostringstream_write_xmlattr_u32(
struct gmio_ostringstream* sstream, const char* attr, uint32_t val);
/*! Write XML element containing \p val : <elt>val</elt> */
void gmio_ostringstream_write_xmlelt_f64(
struct gmio_ostringstream* sstream, const char* elt, double val);
GMIO_INLINE void gmio_ostringstream_write_xmlcdata_open(
struct gmio_ostringstream* sstream);
GMIO_INLINE void gmio_ostringstream_write_xmlcdata_close(
struct gmio_ostringstream* sstream);
/*
* -- Implementation
*/
void gmio_ostringstream_write_char(
struct gmio_ostringstream* sstream, char c)
{
struct gmio_string* strbuff = &sstream->strbuff;
if (strbuff->len >= strbuff->capacity)
gmio_ostringstream_flush(sstream);
strbuff->ptr[strbuff->len] = c;
++strbuff->len;
}
void gmio_ostringstream_flush(struct gmio_ostringstream* sstream)
{
struct gmio_string* strbuff = &sstream->strbuff;
if (strbuff->len > 0) {
/* Don't check bytecount returned is != strbuff->len because some
* write() functions may compress data */
sstream->func_stream_write(
sstream->cookie, &sstream->stream, strbuff->ptr, strbuff->len);
strbuff->len = 0;
}
}
void gmio_ostringstream_write_xmlcdata_open(struct gmio_ostringstream *sstream)
{
gmio_ostringstream_write_chararray(sstream, "<![CDATA[");
}
void gmio_ostringstream_write_xmlcdata_close(struct gmio_ostringstream *sstream)
{
gmio_ostringstream_write_chararray(sstream, "]]>");
}
#endif /* GMIO_INTERNAL_OSTRINGSTREAM_H */

View File

@ -34,16 +34,6 @@
#include <stddef.h>
/*! Stores a read-only string of 8-bit chars
*
* For faster lookups, it knowns the length of its contents.
*/
struct gmio_const_string
{
const char* ptr; /*!< Contents */
size_t len; /*!< Size(length) of current contents */
};
/*! Stores a mutable string of 8-bit chars
*
* For faster lookups, it knowns the length of its contents. Length must not
@ -56,19 +46,6 @@ struct gmio_string
size_t capacity; /*!< Maximum contents size */
};
/*! Expands to bracket initialization of a gmio_const_string from const char[]
*
* Example:
* \code{.c}
* static const char token[] = "woops";
* struct gmio_const_string token_s = GMIO_CONST_STRING_FROM_ARRAY(token);
* \endcode
*/
#define GMIO_CONST_STRING_FROM_ARRAY(array) { &(array)[0], sizeof(array) - 1 }
/*! Returns an initialized struct gmio_const_string object */
GMIO_INLINE struct gmio_const_string gmio_const_string(const char* ptr, size_t len);
/*! Returns an initialized struct gmio_string object
*
* gmio_string::capacity is set to <tt>max(len,capacity)</tt>
@ -99,14 +76,6 @@ GMIO_INLINE char* gmio_cstr_copy(
#include <string.h>
#include "min_max.h"
struct gmio_const_string gmio_const_string(const char* ptr, size_t len)
{
struct gmio_const_string cstr;
cstr.ptr = ptr;
cstr.len = len;
return cstr;
}
struct gmio_string gmio_string(char* ptr, size_t len, size_t capacity)
{
struct gmio_string str;

View File

@ -39,7 +39,8 @@
#include "global.h"
/*! This enum defines the various formats to textually represent a float */
/*! This enum defines the various formats to textually represent a float(single
* or double precision) */
enum gmio_float_text_format
{
/*! Decimal floating point, lowercase (ex: 392.65) */

View File

@ -37,6 +37,7 @@
#include "../../gmio_core/task_iface.h"
#include "../../gmio_core/text_format.h"
#include "../../gmio_core/internal/error_check.h"
#include "../../gmio_core/internal/float_format_utils.h"
#include "../../gmio_core/internal/helper_memblock.h"
#include "../../gmio_core/internal/helper_stream.h"
#include "../../gmio_core/internal/helper_task_iface.h"
@ -117,33 +118,6 @@ GMIO_INLINE char* gmio_write_rawstr_eol(char* buffer, const char* str)
return gmio_write_eol(buffer);
}
GMIO_INLINE char gmio_float_text_format_to_specifier(
enum gmio_float_text_format format)
{
switch (format) {
case GMIO_FLOAT_TEXT_FORMAT_DECIMAL_LOWERCASE: return 'f';
case GMIO_FLOAT_TEXT_FORMAT_DECIMAL_UPPERCASE: return 'F';
case GMIO_FLOAT_TEXT_FORMAT_SCIENTIFIC_LOWERCASE: return 'e';
case GMIO_FLOAT_TEXT_FORMAT_SCIENTIFIC_UPPERCASE: return 'E';
case GMIO_FLOAT_TEXT_FORMAT_SHORTEST_LOWERCASE: return 'g';
case GMIO_FLOAT_TEXT_FORMAT_SHORTEST_UPPERCASE: return 'G';
}
/* Default, should not be here */
return GMIO_FLOAT_TEXT_FORMAT_DECIMAL_LOWERCASE;
}
GMIO_INLINE char* gmio_write_stdio_format(
char* buffer, char format_specifier, uint8_t prec)
{
int prec_len = 0;
buffer[0] = '%';
buffer[1] = '.';
prec_len = sprintf(buffer + 2, "%u", prec);
buffer[2 + prec_len] = format_specifier;
return buffer + 3 + prec_len;
}
struct gmio_vec3f_text_format
{
enum gmio_float_text_format coord_format;
@ -223,13 +197,13 @@ int gmio_stla_write(
{
const uint8_t f32_prec = vec_txtformat.coord_prec;
enum gmio_float_text_format f32_format = opts->stla_float32_format;
const char f32_spec = gmio_float_text_format_to_specifier(f32_format);
const char f32_spec = gmio_float_text_format_to_stdio_specifier(f32_format);
char* buffpos = vec_txtformat.str_printf_format;
buffpos = gmio_write_stdio_format(buffpos, f32_spec, f32_prec);
buffpos = gmio_write_stdio_float_format(buffpos, f32_spec, f32_prec);
buffpos = gmio_write_char(buffpos, ' ');
buffpos = gmio_write_stdio_format(buffpos, f32_spec, f32_prec);
buffpos = gmio_write_stdio_float_format(buffpos, f32_spec, f32_prec);
buffpos = gmio_write_char(buffpos, ' ');
buffpos = gmio_write_stdio_format(buffpos, f32_spec, f32_prec);
buffpos = gmio_write_stdio_float_format(buffpos, f32_spec, f32_prec);
*buffpos = 0;
}

View File

@ -35,6 +35,7 @@
#include "internal/stl_error_check.h"
#include "internal/stla_parsing.h"
#include "../gmio_core/const_string.h"
#include "../gmio_core/error.h"
#include "../gmio_core/internal/c99_stdio_compat.h"
#include "../gmio_core/internal/error_check.h"

View File

@ -32,6 +32,7 @@ set(CMAKE_CTEST_COMMAND ctest -V --timeout 120)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
include_directories(${CMAKE_BINARY_DIR}/src/gmio_core) # For generated cmake headers
include_directories(${ZLIB_INCLUDE_DIRS})
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/temp)
@ -41,7 +42,6 @@ set(GMIO_TEST_CORE_SRC
core_utils.c
stream_buffer.c
../benchmarks/commons/benchmark_tools.c)
add_executable(test_core EXCLUDE_FROM_ALL ${GMIO_TEST_CORE_SRC})
target_link_libraries(test_core gmio_static)
@ -53,10 +53,17 @@ set(GMIO_TEST_STL_SRC
stl_testcases.c
core_utils.c
stl_utils.c)
add_executable(test_stl EXCLUDE_FROM_ALL ${GMIO_TEST_STL_SRC})
target_link_libraries(test_stl gmio_static)
# test_amf
set(GMIO_TEST_AMF_SRC
main_test_amf.c
stream_buffer.c)
add_executable(test_amf EXCLUDE_FROM_ALL ${GMIO_TEST_AMF_SRC})
target_link_libraries(test_amf gmio_static)
target_link_libraries(test_amf ${ZLIB_LIBRARIES})
# fake_support
if(GMIO_BUILD_TESTS_FAKE_SUPPORT)
add_subdirectory(fake_support)
@ -72,5 +79,5 @@ endif()
# Declare tests
add_test(NAME test_core COMMAND test_core)
add_test(NAME test_stl COMMAND test_stl)
add_dependencies(check test_core test_stl)
add_test(NAME test_amf COMMAND test_amf)
add_dependencies(check test_core test_stl test_amf)

55
tests/main_test_amf.c Normal file
View File

@ -0,0 +1,55 @@
/****************************************************************************
** 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_lib.h"
#include "../src/gmio_core/global.h"
#include "../src/gmio_core/memblock.h"
#include "test_amf_io.c"
#include <stddef.h>
/* Static memblock */
struct gmio_memblock gmio_memblock_for_tests()
{
return gmio_memblock_malloc(512 * 1024); /* 512KB */
}
const char* all_tests()
{
UTEST_SUITE_START();
gmio_memblock_set_default_constructor(gmio_memblock_for_tests);
UTEST_RUN(test_amf_write);
return NULL;
}
UTEST_MAIN(all_tests)

View File

@ -51,6 +51,7 @@ const char* all_tests()
UTEST_RUN(test_internal__fast_atof);
UTEST_RUN(test_internal__locale_utils);
UTEST_RUN(test_internal__error_check);
UTEST_RUN(test_internal__ostringstream);
UTEST_RUN(test_internal__safe_cast);
UTEST_RUN(test_internal__stringstream);
UTEST_RUN(test_internal__string_ascii_utils);

View File

@ -52,6 +52,6 @@ struct gmio_ro_buffer gmio_ro_buffer(const void* ptr, size_t len, size_t pos);
struct gmio_rw_buffer gmio_rw_buffer(void* ptr, size_t len, size_t pos);
struct gmio_stream gmio_istream_buffer(struct gmio_ro_buffer* buff);
struct gmio_stream gmio_iostream_buffer(struct gmio_rw_buffer* buff);
struct gmio_stream gmio_stream_buffer(struct gmio_rw_buffer* buff);
#endif /* GMIO_STREAM_BUFFER_H */

268
tests/test_amf_io.c Normal file
View File

@ -0,0 +1,268 @@
/****************************************************************************
** 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/helper_stream.h"
#include "../src/gmio_amf/amf_error.h"
#include "../src/gmio_amf/amf_io.h"
#include <stddef.h>
#include <stdio.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)
{
const struct __tamf__document* doc =
(const struct __tamf__document*)cookie;
GMIO_UNUSED(object_index);
GMIO_UNUSED(mesh_index);
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)
{
const struct __tamf__document* doc = (const struct __tamf__document*)cookie;
const struct __tamf__triangle* tri = &doc->mesh.vec_triangle[triangle_index];
GMIO_UNUSED(volume_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)
{
const struct __tamf__document* doc = (const struct __tamf__document*)cookie;
GMIO_UNUSED(metadata_index);
if (element == GMIO_AMF_DOCUMENT_ELEMENT_MATERIAL) {
ptr_metadata->type = "name";
ptr_metadata->data = doc->vec_material[element_index].name;
}
}
static const char* test_amf_write()
{
{
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));
}
{
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 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) */
{
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);
}
#if 0
/* Write compressed */
{
int error = GMIO_ERROR_OK;
wbuff.pos = 0;
options.compress = true;
error = gmio_amf_write(&stream, &doc, &options);
UTEST_COMPARE_INT(error, GMIO_ERROR_OK);
}
#endif
free(wbuff.ptr);
}
return NULL;
}

View File

@ -39,6 +39,7 @@
#include "../src/gmio_core/internal/fast_atof.h"
#include "../src/gmio_core/internal/locale_utils.h"
#include "../src/gmio_core/internal/numeric_utils.h"
#include "../src/gmio_core/internal/ostringstream.h"
#include "../src/gmio_core/internal/safe_cast.h"
#include "../src/gmio_core/internal/stringstream.h"
#include "../src/gmio_core/internal/stringstream_fast_atof.h"
@ -282,6 +283,89 @@ static const char* test_internal__stringstream()
return NULL;
}
static const char* test_internal__ostringstream()
{
static const size_t size = 8192;
char* input = malloc(size);
char* output = malloc(size);
char strbuff[256] = {0};
struct gmio_rw_buffer rwbuff = gmio_rw_buffer(output, size, 0);
struct gmio_ostringstream sstream =
gmio_ostringstream(
gmio_stream_buffer(&rwbuff),
gmio_string(strbuff, 0, sizeof(strbuff) - 1));
{ /* Create "input" string */
size_t i = 0;
for (i = 0; i < size; ++i) {
const char c = 32 + (i % 94); /* Printable ASCII chars */
input[i] = c;
}
/* Test gmio_ostringstream_write_char() */
for (i = 0; i < size; ++i)
gmio_ostringstream_write_char(&sstream, input[i]);
gmio_ostringstream_flush(&sstream);
UTEST_ASSERT(strncmp(input, output, size) == 0);
/* Test gmio_ostringstream_write_[ui]32() */
{
static const char result[] =
"20 12345 0 -1 -12345678 4294967295 2147483647";
static const unsigned result_len = sizeof(result) - 1;
rwbuff.pos = 0;
gmio_ostringstream_write_u32(&sstream, 20);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_u32(&sstream, 12345);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_u32(&sstream, 0);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_i32(&sstream, -1);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_i32(&sstream, -12345678);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_u32(&sstream, (uint32_t)-1);
gmio_ostringstream_write_char(&sstream, ' ');
gmio_ostringstream_write_i32(&sstream, ((uint32_t)1 << 31) - 1);
gmio_ostringstream_flush(&sstream);
UTEST_ASSERT(strncmp(result, sstream.strbuff.ptr, result_len) == 0);
UTEST_ASSERT(strncmp(result, output, result_len) == 0);
}
/* Test gmio_ostringstream_write_base64() */
{
static const char str[] = "Fougue+gmio";
static const char str_b64[] = "Rm91Z3VlK2dtaW8=";
static const unsigned str_len = sizeof(str) - 1;
static const unsigned str_b64_len = sizeof(str_b64) - 1;
rwbuff.pos = 0;
gmio_ostringstream_write_base64(
&sstream, (unsigned const char*)str, str_len);
gmio_ostringstream_flush(&sstream);
UTEST_ASSERT(strncmp(str_b64, sstream.strbuff.ptr, str_b64_len) == 0);
UTEST_ASSERT(strncmp(str_b64, output, str_b64_len) == 0);
}
/* Test gmio_ostringstream_write_xml...() */
{
static const char result[] =
" foo=\"crac\" bar=\"456789\"<![CDATA[]]>";
static const unsigned result_len = sizeof(result) - 1;
rwbuff.pos = 0;
gmio_ostringstream_write_xmlattr_str(&sstream, "foo", "crac");
gmio_ostringstream_write_xmlattr_u32(&sstream, "bar", 456789);
gmio_ostringstream_write_xmlcdata_open(&sstream);
gmio_ostringstream_write_xmlcdata_close(&sstream);
gmio_ostringstream_flush(&sstream);
UTEST_ASSERT(strncmp(result, sstream.strbuff.ptr, result_len) == 0);
UTEST_ASSERT(strncmp(result, output, result_len) == 0);
}
}
free(input);
free(output);
return NULL;
}
static const char* test_internal__string_ascii_utils()
{
char c; /* for loop counter */