parent
091f665a6d
commit
456eddc520
@ -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"))
|
||||
|
@ -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
258
src/3rdparty/base64/b64.c
vendored
Normal 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
9
src/3rdparty/base64/b64.h
vendored
Normal 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
293
src/3rdparty/miloyip_itoa/branchlut.c
vendored
Normal 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
13
src/3rdparty/miloyip_itoa/branchlut.h
vendored
Normal 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 */
|
@ -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
367
src/gmio_amf/amf_document.h
Normal 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
88
src/gmio_amf/amf_error.h
Normal 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
66
src/gmio_amf/amf_global.h
Normal 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
944
src/gmio_amf/amf_io.c
Normal 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
85
src/gmio_amf/amf_io.h
Normal 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 */
|
||||
/*! @} */
|
136
src/gmio_amf/amf_io_options.h
Normal file
136
src/gmio_amf/amf_io_options.h
Normal 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 */
|
87
src/gmio_core/const_string.h
Normal file
87
src/gmio_core/const_string.h
Normal 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 */
|
@ -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
|
||||
|
||||
|
67
src/gmio_core/internal/float_format_utils.c
Normal file
67
src/gmio_core/internal/float_format_utils.c
Normal 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;
|
||||
}
|
45
src/gmio_core/internal/float_format_utils.h
Normal file
45
src/gmio_core/internal/float_format_utils.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
76
src/gmio_core/internal/itoa.h
Normal file
76
src/gmio_core/internal/itoa.h
Normal 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 */
|
214
src/gmio_core/internal/ostringstream.c
Normal file
214
src/gmio_core/internal/ostringstream.c
Normal 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;
|
||||
}
|
||||
}
|
180
src/gmio_core/internal/ostringstream.h
Normal file
180
src/gmio_core/internal/ostringstream.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
55
tests/main_test_amf.c
Normal 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)
|
@ -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);
|
||||
|
@ -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
268
tests/test_amf_io.c
Normal 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;
|
||||
}
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user