mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 10:48:56 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ff44b903c | ||
|
|
381daedaba | ||
|
|
34a166cdac | ||
|
|
0e3043f3e9 |
11
.github/workflows/c-cpp.yml
vendored
11
.github/workflows/c-cpp.yml
vendored
@@ -66,10 +66,12 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
cmake --help
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On -DTINYGLTF_BUILD_TESTS=ON ..
|
||||
cd ..
|
||||
- name: Build
|
||||
run: cmake --build build --config Release
|
||||
- name: Run tests
|
||||
run: ctest --test-dir build -C Release --output-on-failure
|
||||
|
||||
|
||||
build-linux:
|
||||
@@ -109,6 +111,12 @@ jobs:
|
||||
cc -I../ -std=c11 -g -O0 -DTINYGLTF3_ENABLE_FS \
|
||||
-o tester_v3_c_v1port tester_v3_c_v1port.c ../tiny_gltf_v3.c
|
||||
./tester_v3_c_v1port
|
||||
cc -I../ -std=c11 -g -O0 \
|
||||
-o tester_v3_json_c tester_v3_json_c.c
|
||||
./tester_v3_json_c
|
||||
cc -I../ -std=c11 -ffreestanding -g -O0 \
|
||||
-o tester_v3_freestanding tester_v3_freestanding.c
|
||||
./tester_v3_freestanding
|
||||
cd ..
|
||||
|
||||
|
||||
@@ -177,4 +185,3 @@ jobs:
|
||||
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
clang++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
|
||||
42
.github/workflows/ci.yml
vendored
42
.github/workflows/ci.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -B build -DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON
|
||||
cmake -B build -DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON
|
||||
run: cmake -B build -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=Off ..
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=Off -DTINYGLTF_BUILD_TESTS=ON ..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config Release
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 17 2022" -A Win32 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=Off ..
|
||||
cmake -G "Visual Studio 17 2022" -A Win32 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=Off -DTINYGLTF_BUILD_TESTS=ON ..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config Release
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
|
||||
- name: Build with CMake
|
||||
run: |
|
||||
cmake -G"Ninja" -S . -B build
|
||||
cmake -G"Ninja" -S . -B build -DTINYGLTF_BUILD_TESTS=ON
|
||||
cmake --build build
|
||||
|
||||
- name: Run loader_example
|
||||
@@ -249,7 +249,7 @@ jobs:
|
||||
- name: Build with CMake Header-Only
|
||||
run: |
|
||||
mkdir build
|
||||
cmake -B build -DTINYGLTF_HEADER_ONLY=ON -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON
|
||||
cmake -B build -DTINYGLTF_HEADER_ONLY=ON -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON
|
||||
cmake --build build
|
||||
|
||||
- name: Run loader_example
|
||||
@@ -259,6 +259,30 @@ jobs:
|
||||
- name: Run tests
|
||||
run: ctest --test-dir build --output-on-failure
|
||||
|
||||
# v3 C tests through Meson on the primary desktop platforms.
|
||||
v3-c-meson:
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: v3 C Meson (${{ matrix.os }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Meson
|
||||
run: python -m pip install meson ninja
|
||||
|
||||
- name: Configure
|
||||
run: meson setup build-meson -Dtests=true
|
||||
|
||||
- name: Build
|
||||
run: meson compile -C build-meson
|
||||
|
||||
- name: Run v3 C tests
|
||||
run: meson test -C build-meson --print-errorlogs
|
||||
|
||||
# Special Configuration: RapidJSON Backend
|
||||
linux-rapidjson:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -273,7 +297,7 @@ jobs:
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -B build -DTINYGLTF_USE_RAPIDJSON=ON -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DCMAKE_PREFIX_PATH=$PWD/rapidjson
|
||||
cmake -B build -DTINYGLTF_USE_RAPIDJSON=ON -DTINYGLTF_BUILD_LOADER_EXAMPLE=ON -DTINYGLTF_BUILD_TESTS=ON -DCMAKE_PREFIX_PATH=$PWD/rapidjson
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
10
.github/workflows/mingw-w64-msys2.yml
vendored
10
.github/workflows/mingw-w64-msys2.yml
vendored
@@ -7,7 +7,11 @@ on:
|
||||
- devel
|
||||
paths:
|
||||
- 'tiny_gltf.*'
|
||||
- 'tinygltf_json_c.h'
|
||||
- 'CMakeLists.txt'
|
||||
- 'meson.build'
|
||||
- 'meson_options.txt'
|
||||
- 'tests/tester_v3*.c'
|
||||
- '.github/workflows/mingw-w64-msys2.yml'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
@@ -37,9 +41,13 @@ jobs:
|
||||
cmake \
|
||||
-G"Ninja" \
|
||||
-S . \
|
||||
-B build
|
||||
-B build \
|
||||
-DTINYGLTF_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build build
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
ctest --test-dir build --output-on-failure
|
||||
|
||||
@@ -41,6 +41,21 @@ endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
||||
|
||||
if (TINYGLTF_BUILD_TESTS)
|
||||
enable_testing()
|
||||
|
||||
function(add_tinygltf_v3_c_test target)
|
||||
add_executable(${target} ${ARGN})
|
||||
target_include_directories(${target} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests
|
||||
)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
C_EXTENSIONS OFF
|
||||
)
|
||||
add_test(NAME ${target} COMMAND ${target} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||
endfunction()
|
||||
|
||||
add_executable(tester tests/tester.cc)
|
||||
target_include_directories(tester PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@@ -66,20 +81,18 @@ if (TINYGLTF_BUILD_TESTS)
|
||||
target_compile_definitions(tester_intensive_customjson PRIVATE TINYGLTF_USE_CUSTOM_JSON)
|
||||
add_test(NAME tester_intensive_customjson COMMAND tester_intensive_customjson WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||
|
||||
add_executable(tester_v3_c
|
||||
tests/tester_v3_c.c
|
||||
tiny_gltf_v3.c
|
||||
)
|
||||
target_include_directories(tester_v3_c PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests
|
||||
)
|
||||
set_target_properties(tester_v3_c PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
C_EXTENSIONS OFF
|
||||
)
|
||||
add_test(NAME tester_v3_c COMMAND tester_v3_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||
add_tinygltf_v3_c_test(tester_v3_c tests/tester_v3_c.c tiny_gltf_v3.c)
|
||||
target_compile_definitions(tester_v3_c PRIVATE TINYGLTF3_ENABLE_FS)
|
||||
|
||||
add_tinygltf_v3_c_test(tester_v3_c_v1port tests/tester_v3_c_v1port.c tiny_gltf_v3.c)
|
||||
target_compile_definitions(tester_v3_c_v1port PRIVATE TINYGLTF3_ENABLE_FS)
|
||||
|
||||
add_tinygltf_v3_c_test(tester_v3_json_c tests/tester_v3_json_c.c)
|
||||
|
||||
add_tinygltf_v3_c_test(tester_v3_freestanding tests/tester_v3_freestanding.c)
|
||||
if (CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
|
||||
target_compile_options(tester_v3_freestanding PRIVATE -ffreestanding)
|
||||
endif()
|
||||
endif (TINYGLTF_BUILD_TESTS)
|
||||
|
||||
#
|
||||
|
||||
@@ -61,8 +61,10 @@ The v3 C runtime is built for processing **untrusted glTF/GLB input** (server-si
|
||||
|
||||
- **URI sanitization** — external buffer/image URIs are rejected before any filesystem call if they are empty, contain NUL bytes, begin with `/` or `\`, look like a Windows drive prefix (`X:`), or contain a `..` segment. Production callers SHOULD still provide a custom `tg3_fs_callbacks.read_file` that confines reads to a known directory (e.g. via `openat` plus a `realpath` prefix check) when the input is attacker-controlled.
|
||||
- **Index bounds validation** — every `int32_t` index field populated from JSON (accessor.bufferView, primitive.indices/material/attributes, scene.nodes[], skin.joints[], animation channel/sampler refs, KHR_audio + MSFT_lod refs, …) is checked after the structural parse. Out-of-range indices produce `TG3_ERR_INVALID_INDEX`. Default `tg3_parse_options.validate_indices = 1`; set to `0` only when you need raw round-trip and have your own validator.
|
||||
- **Buffer/accessor range validation** — declared buffer lengths, bufferView ranges, accessor element spans, sparse accessor spans, component types, and overflow-prone size math are checked before returning a model.
|
||||
- **Strict numeric range checks** — JSON numbers feeding integer fields go through finite/round-trip-validated coercion (`tg3__json_number_to_int32` / `_uint64`). `byteStride` is restricted to 0 or [4, 252].
|
||||
- **Memory budget** — the arena is capped at `TINYGLTF3_MAX_MEMORY_BYTES` (1 GB by default; configurable via `tg3_memory_config`).
|
||||
- **Memory budget** — the arena and C JSON parser enforce `TINYGLTF3_MAX_MEMORY_BYTES` by default; `max_single_alloc` and `TINYGLTF3_MAX_STRING_LENGTH` bound individual allocation and string size.
|
||||
- **Opt-in fast paths** — `skip_extras_values` avoids materializing `extras` and unknown extension value trees, and `borrow_input_buffers` lets GLB buffer spans reference caller-owned input bytes instead of copying the BIN chunk.
|
||||
- **Image decoding off by default** — the parser does not decode image bytes; use `tg3_parse_options.images_as_is = 1` to skip any decoder entirely when handling untrusted input.
|
||||
- **Error message lifetime** — error strings on `tg3_error_stack` are arena-allocated and remain valid until `tg3_model_free()`. Read or copy them BEFORE freeing the model.
|
||||
|
||||
|
||||
@@ -139,7 +139,9 @@ struct BenchResult {
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static BenchResult bench_file(const char *filename, int iterations, int warmup,
|
||||
bool quiet, int float32_mode = 0) {
|
||||
bool quiet, int float32_mode = 0,
|
||||
int skip_extras_values = 0,
|
||||
int borrow_input_buffers = 0) {
|
||||
BenchResult r = {};
|
||||
r.filename = filename;
|
||||
r.iterations = iterations;
|
||||
@@ -199,6 +201,8 @@ static BenchResult bench_file(const char *filename, int iterations, int warmup,
|
||||
opts.memory.allocator.free = tracked_free;
|
||||
opts.memory.allocator.user_data = &tracker;
|
||||
opts.parse_float32 = float32_mode;
|
||||
opts.skip_extras_values = skip_extras_values;
|
||||
opts.borrow_input_buffers = borrow_input_buffers;
|
||||
|
||||
tg3_model model;
|
||||
tg3_error_stack errors;
|
||||
@@ -340,7 +344,11 @@ static void usage() {
|
||||
" --csv Output in CSV format\n"
|
||||
" --quiet Suppress per-iteration error messages\n"
|
||||
" --batch Benchmark multiple files\n"
|
||||
" --float32 Parse JSON floats as float32 (faster, less precise)\n");
|
||||
" --float32 Parse JSON floats as float32 (faster, less precise)\n"
|
||||
" --skip-extras-values\n"
|
||||
" Skip materializing extras/unknown extension values\n"
|
||||
" --borrow-input-buffers\n"
|
||||
" Let GLB buffers reference caller-owned input bytes\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -351,6 +359,8 @@ int main(int argc, char **argv) {
|
||||
bool csv = false;
|
||||
bool quiet = false;
|
||||
int float32_mode = 0;
|
||||
int skip_extras_values = 0;
|
||||
int borrow_input_buffers = 0;
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
@@ -364,6 +374,10 @@ int main(int argc, char **argv) {
|
||||
quiet = true;
|
||||
} else if (strcmp(argv[i], "--float32") == 0) {
|
||||
float32_mode = 1;
|
||||
} else if (strcmp(argv[i], "--skip-extras-values") == 0) {
|
||||
skip_extras_values = 1;
|
||||
} else if (strcmp(argv[i], "--borrow-input-buffers") == 0) {
|
||||
borrow_input_buffers = 1;
|
||||
} else if (strcmp(argv[i], "--batch") == 0) {
|
||||
/* batch mode: just collect files */
|
||||
} else if (argv[i][0] != '-') {
|
||||
@@ -379,10 +393,14 @@ int main(int argc, char **argv) {
|
||||
if (!csv && !quiet) {
|
||||
printf("Benchmarking: %s (%d iterations, %d warmup%s)\n",
|
||||
file.c_str(), iterations, warmup,
|
||||
float32_mode ? ", float32" : "");
|
||||
float32_mode ? ", float32" :
|
||||
skip_extras_values ? ", skip extras" :
|
||||
borrow_input_buffers ? ", borrow buffers" : "");
|
||||
}
|
||||
|
||||
BenchResult r = bench_file(file.c_str(), iterations, warmup, quiet, float32_mode);
|
||||
BenchResult r = bench_file(file.c_str(), iterations, warmup, quiet,
|
||||
float32_mode, skip_extras_values,
|
||||
borrow_input_buffers);
|
||||
|
||||
if (csv) {
|
||||
print_csv_row(r);
|
||||
|
||||
52
meson.build
Normal file
52
meson.build
Normal file
@@ -0,0 +1,52 @@
|
||||
project(
|
||||
'tinygltf',
|
||||
'c',
|
||||
default_options: ['c_std=c11'],
|
||||
meson_version: '>=0.55.0',
|
||||
)
|
||||
|
||||
tinygltf_inc = include_directories('.', 'tests')
|
||||
|
||||
if get_option('tests')
|
||||
tests_workdir = join_paths(meson.current_source_dir(), 'tests')
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
tester_v3_c = executable(
|
||||
'tester_v3_c',
|
||||
['tests/tester_v3_c.c', 'tiny_gltf_v3.c'],
|
||||
include_directories: tinygltf_inc,
|
||||
c_args: ['-DTINYGLTF3_ENABLE_FS'],
|
||||
install: false,
|
||||
)
|
||||
test('tester_v3_c', tester_v3_c, workdir: tests_workdir)
|
||||
|
||||
tester_v3_c_v1port = executable(
|
||||
'tester_v3_c_v1port',
|
||||
['tests/tester_v3_c_v1port.c', 'tiny_gltf_v3.c'],
|
||||
include_directories: tinygltf_inc,
|
||||
c_args: ['-DTINYGLTF3_ENABLE_FS'],
|
||||
install: false,
|
||||
)
|
||||
test('tester_v3_c_v1port', tester_v3_c_v1port, workdir: tests_workdir)
|
||||
|
||||
tester_v3_json_c = executable(
|
||||
'tester_v3_json_c',
|
||||
'tests/tester_v3_json_c.c',
|
||||
include_directories: tinygltf_inc,
|
||||
install: false,
|
||||
)
|
||||
test('tester_v3_json_c', tester_v3_json_c, workdir: tests_workdir)
|
||||
|
||||
freestanding_args = []
|
||||
if cc.get_id() in ['clang', 'gcc']
|
||||
freestanding_args += ['-ffreestanding']
|
||||
endif
|
||||
tester_v3_freestanding = executable(
|
||||
'tester_v3_freestanding',
|
||||
'tests/tester_v3_freestanding.c',
|
||||
include_directories: tinygltf_inc,
|
||||
c_args: freestanding_args,
|
||||
install: false,
|
||||
)
|
||||
test('tester_v3_freestanding', tester_v3_freestanding, workdir: tests_workdir)
|
||||
endif
|
||||
1
meson_options.txt
Normal file
1
meson_options.txt
Normal file
@@ -0,0 +1 @@
|
||||
option('tests', type: 'boolean', value: true, description: 'Build and run tinygltf tests')
|
||||
@@ -1,7 +1,7 @@
|
||||
# Use this for strict compilation check(will work on clang 3.8+)
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -DTINYGLTF_APPLY_CLANG_WEVERYTHING
|
||||
|
||||
all: ../tiny_gltf.h tester_v3_c tester_v3_c_v1port
|
||||
all: ../tiny_gltf.h tester_v3_c tester_v3_c_v1port tester_v3_json_c tester_v3_freestanding
|
||||
clang++ -I../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o tester tester.cc
|
||||
clang++ -DTINYGLTF_NOEXCEPTION -I../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
clang++ -DTINYGLTF_USE_CUSTOM_JSON -I../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o tester_intensive_customjson tester_intensive_customjson.cc
|
||||
@@ -11,3 +11,9 @@ tester_v3_c: tester_v3_c.c ../tiny_gltf_v3.h ../tiny_gltf_v3.c ../tinygltf_json_
|
||||
|
||||
tester_v3_c_v1port: tester_v3_c_v1port.c ../tiny_gltf_v3.h ../tiny_gltf_v3.c ../tinygltf_json_c.h
|
||||
clang -I../ -std=c11 -g -O0 -DTINYGLTF3_ENABLE_FS -o tester_v3_c_v1port tester_v3_c_v1port.c ../tiny_gltf_v3.c
|
||||
|
||||
tester_v3_json_c: tester_v3_json_c.c ../tinygltf_json_c.h
|
||||
clang -I../ -std=c11 -g -O0 -o tester_v3_json_c tester_v3_json_c.c
|
||||
|
||||
tester_v3_freestanding: tester_v3_freestanding.c ../tiny_gltf_v3.h ../tiny_gltf_v3.c ../tinygltf_json_c.h
|
||||
clang -I../ -std=c11 -ffreestanding -g -O0 -o tester_v3_freestanding tester_v3_freestanding.c
|
||||
|
||||
1029
tests/tester_v3_c.c
1029
tests/tester_v3_c.c
File diff suppressed because it is too large
Load Diff
75
tests/tester_v3_freestanding.c
Normal file
75
tests/tester_v3_freestanding.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static union {
|
||||
uint64_t align;
|
||||
unsigned char bytes[512 * 1024];
|
||||
} test_heap;
|
||||
static size_t test_heap_used;
|
||||
|
||||
static void *test_malloc(size_t size) {
|
||||
size_t total = (size + sizeof(size_t) + 7u) & ~(size_t)7u;
|
||||
if (test_heap_used + total > sizeof(test_heap.bytes)) return 0;
|
||||
{
|
||||
unsigned char *base = test_heap.bytes + test_heap_used;
|
||||
*((size_t *)base) = size;
|
||||
test_heap_used += total;
|
||||
return base + sizeof(size_t);
|
||||
}
|
||||
}
|
||||
|
||||
static void *test_realloc(void *ptr, size_t size) {
|
||||
unsigned char *old_base;
|
||||
size_t old_size;
|
||||
unsigned char *new_ptr;
|
||||
size_t n;
|
||||
size_t i;
|
||||
if (!ptr) return test_malloc(size);
|
||||
old_base = (unsigned char *)ptr - sizeof(size_t);
|
||||
old_size = *((size_t *)old_base);
|
||||
new_ptr = (unsigned char *)test_malloc(size);
|
||||
if (!new_ptr) return 0;
|
||||
n = old_size < size ? old_size : size;
|
||||
for (i = 0; i < n; ++i) new_ptr[i] = ((unsigned char *)ptr)[i];
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
static void test_free(void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
#define TINYGLTF3_NO_STDLIB
|
||||
#define TINYGLTF3_MALLOC(sz) test_malloc(sz)
|
||||
#define TINYGLTF3_REALLOC(ptr, sz) test_realloc((ptr), (sz))
|
||||
#define TINYGLTF3_FREE(ptr) test_free(ptr)
|
||||
#define TINYGLTF3_IMPLEMENTATION
|
||||
#include "tiny_gltf_v3.h"
|
||||
|
||||
static int streq(tg3_str s, const char *lit, uint32_t len) {
|
||||
uint32_t i;
|
||||
if (!s.data || s.len != len) return 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (s.data[i] != lit[i]) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
static const uint8_t json[] =
|
||||
"{\"asset\":{\"version\":\"2.0\"},\"nodes\":[{\"name\":\"free\"}]}";
|
||||
tg3_model model;
|
||||
tg3_error_stack errors;
|
||||
tg3_parse_options opts;
|
||||
tg3_error_code err;
|
||||
|
||||
tg3_error_stack_init(&errors);
|
||||
tg3_parse_options_init(&opts);
|
||||
err = tg3_parse_auto(&model, &errors, json, (uint64_t)(sizeof(json) - 1),
|
||||
"", 0, &opts);
|
||||
if (err != TG3_OK) return 1;
|
||||
if (model.nodes_count != 1) return 3;
|
||||
if (!streq(model.nodes[0].name, "free", 4)) return 4;
|
||||
tg3_model_free(&model);
|
||||
tg3_error_stack_free(&errors);
|
||||
return 0;
|
||||
}
|
||||
165
tests/tester_v3_json_c.c
Normal file
165
tests/tester_v3_json_c.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TINYGLTF_JSON_C_IMPLEMENTATION
|
||||
#include "tinygltf_json_c.h"
|
||||
|
||||
static uint64_t dbl_bits(double v) {
|
||||
uint64_t bits;
|
||||
memcpy(&bits, &v, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
|
||||
static double dbl_from_bits(uint64_t bits) {
|
||||
double v;
|
||||
memcpy(&v, &bits, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static int check_stringify(const char *json, const char *expected) {
|
||||
tg3json_value v;
|
||||
const char *err = NULL;
|
||||
char *out;
|
||||
size_t out_len = 0;
|
||||
int ok = 1;
|
||||
if (!tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
|
||||
fprintf(stderr, "parse failed for %s at %td\n", json, err ? err - json : -1);
|
||||
return 0;
|
||||
}
|
||||
out = tg3json_stringify(&v, &out_len);
|
||||
if (!out || strcmp(out, expected) != 0) {
|
||||
fprintf(stderr, "stringify(%s) = %s, expected %s\n",
|
||||
json, out ? out : "(null)", expected);
|
||||
ok = 0;
|
||||
}
|
||||
if (out) TINYGLTF_JSON_FREE(out);
|
||||
tg3json_value_free(&v);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int check_parse_rejects(const char *json) {
|
||||
tg3json_value v;
|
||||
const char *err = NULL;
|
||||
if (tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
|
||||
fprintf(stderr, "parse unexpectedly accepted %s\n", json);
|
||||
tg3json_value_free(&v);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_roundtrip(const char *json) {
|
||||
tg3json_value a;
|
||||
tg3json_value b;
|
||||
const char *err = NULL;
|
||||
char *out;
|
||||
size_t out_len = 0;
|
||||
int ok = 1;
|
||||
if (!tg3json_parse(json, json + strlen(json), 128, &a, &err)) return 0;
|
||||
out = tg3json_stringify(&a, &out_len);
|
||||
if (!out || !tg3json_parse(out, out + out_len, 128, &b, &err)) {
|
||||
ok = 0;
|
||||
} else if (a.type != TG3JSON_REAL ||
|
||||
!((b.type == TG3JSON_REAL && dbl_bits(a.u.real) == dbl_bits(b.u.real)) ||
|
||||
(b.type == TG3JSON_INT && dbl_bits(a.u.real) == dbl_bits((double)b.u.integer)))) {
|
||||
fprintf(stderr, "roundtrip changed bits: %s -> %s\n", json, out);
|
||||
ok = 0;
|
||||
}
|
||||
if (out) TINYGLTF_JSON_FREE(out);
|
||||
tg3json_value_free(&a);
|
||||
tg3json_value_free(&b);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int check_parse_bits(const char *json, uint64_t expected_bits) {
|
||||
tg3json_value v;
|
||||
const char *err = NULL;
|
||||
if (!tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
|
||||
fprintf(stderr, "parse failed for %s at %td\n", json, err ? err - json : -1);
|
||||
return 0;
|
||||
}
|
||||
if (v.type != TG3JSON_REAL || dbl_bits(v.u.real) != expected_bits) {
|
||||
fprintf(stderr, "parse bits mismatch: %s -> 0x%llx, expected 0x%llx\n",
|
||||
json, (unsigned long long)(v.type == TG3JSON_REAL ? dbl_bits(v.u.real) : 0),
|
||||
(unsigned long long)expected_bits);
|
||||
tg3json_value_free(&v);
|
||||
return 0;
|
||||
}
|
||||
tg3json_value_free(&v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_parse_float32(void) {
|
||||
static const char json[] = "0.10000000149011612";
|
||||
tg3json_parse_options opts;
|
||||
tg3json_value v;
|
||||
const char *err = NULL;
|
||||
double expected = (double)(float)0.10000000149011612;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.parse_float32 = 1;
|
||||
if (!tg3json_parse_n_opts(json, strlen(json), &opts, &v, &err)) {
|
||||
fprintf(stderr, "parse_float32 parse failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (v.type != TG3JSON_REAL || dbl_bits(v.u.real) != dbl_bits(expected)) {
|
||||
fprintf(stderr, "parse_float32 did not round through float\n");
|
||||
tg3json_value_free(&v);
|
||||
return 0;
|
||||
}
|
||||
tg3json_value_free(&v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_nonfinite_stringifies_to_null(void) {
|
||||
tg3json_value v;
|
||||
char *out;
|
||||
size_t len = 0;
|
||||
int ok;
|
||||
tg3json_value_init_real(&v, dbl_from_bits(0x7ff0000000000000ULL));
|
||||
out = tg3json_stringify(&v, &len);
|
||||
ok = out && strcmp(out, "null") == 0;
|
||||
if (!ok) fprintf(stderr, "inf stringify = %s\n", out ? out : "(null)");
|
||||
if (out) TINYGLTF_JSON_FREE(out);
|
||||
tg3json_value_free(&v);
|
||||
if (!ok) return 0;
|
||||
|
||||
tg3json_value_init_real(&v, dbl_from_bits(0x7ff8000000000001ULL));
|
||||
out = tg3json_stringify(&v, &len);
|
||||
ok = out && strcmp(out, "null") == 0;
|
||||
if (!ok) fprintf(stderr, "nan stringify = %s\n", out ? out : "(null)");
|
||||
if (out) TINYGLTF_JSON_FREE(out);
|
||||
tg3json_value_free(&v);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int ok = 1;
|
||||
ok = check_stringify("1.0", "1") && ok;
|
||||
ok = check_stringify("-1.0", "-1") && ok;
|
||||
ok = check_stringify("0.1", "0.1") && ok;
|
||||
ok = check_stringify("0.0001", "0.0001") && ok;
|
||||
ok = check_stringify("0.00001", "1e-5") && ok;
|
||||
ok = check_stringify("1000000000000000.0", "1000000000000000") && ok;
|
||||
ok = check_stringify("10000000000000000.0", "1e16") && ok;
|
||||
ok = check_roundtrip("1.2345678901234567") && ok;
|
||||
ok = check_roundtrip("2.2250738585072014e-308") && ok;
|
||||
ok = check_roundtrip("5e-324") && ok;
|
||||
ok = check_roundtrip("-5e-324") && ok;
|
||||
ok = check_roundtrip("9007199254740993.0") && ok;
|
||||
ok = check_parse_bits("1.23456789012345678901", 0x3ff3c0ca428c59fbULL) && ok;
|
||||
ok = check_parse_bits("1.234567890123456789012345678901234567890e-100",
|
||||
0x2b31482fe620c5d2ULL) && ok;
|
||||
ok = check_parse_bits("1.7976931348623157e308", 0x7fefffffffffffffULL) && ok;
|
||||
ok = check_parse_float32() && ok;
|
||||
ok = check_nonfinite_stringifies_to_null() && ok;
|
||||
ok = check_parse_rejects("+1") && ok;
|
||||
ok = check_parse_rejects("01") && ok;
|
||||
ok = check_parse_rejects("1.") && ok;
|
||||
ok = check_parse_rejects("1e") && ok;
|
||||
ok = check_parse_rejects("1e400") && ok;
|
||||
ok = check_parse_rejects("-1e400") && ok;
|
||||
ok = check_parse_rejects("1.7976931348623159e308") && ok;
|
||||
ok = check_parse_rejects("[1,]") && ok;
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
647
tiny_gltf_v3.c
647
tiny_gltf_v3.c
File diff suppressed because it is too large
Load Diff
@@ -116,8 +116,12 @@
|
||||
|
||||
/* Assert override */
|
||||
#ifndef TINYGLTF3_ASSERT
|
||||
#ifndef TINYGLTF3_NO_STDLIB
|
||||
#include <assert.h>
|
||||
#define TINYGLTF3_ASSERT(x) assert(x)
|
||||
#else
|
||||
#define TINYGLTF3_ASSERT(x) ((void)(x))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ======================================================================
|
||||
@@ -127,8 +131,34 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#ifndef TINYGLTF3_NO_STDLIB
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF3_MALLOC
|
||||
#ifndef TINYGLTF3_NO_STDLIB
|
||||
#define TINYGLTF3_MALLOC(sz) malloc(sz)
|
||||
#else
|
||||
#define TINYGLTF3_MALLOC(sz) NULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF3_REALLOC
|
||||
#ifndef TINYGLTF3_NO_STDLIB
|
||||
#define TINYGLTF3_REALLOC(ptr, sz) realloc((ptr), (sz))
|
||||
#else
|
||||
#define TINYGLTF3_REALLOC(ptr, sz) NULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF3_FREE
|
||||
#ifndef TINYGLTF3_NO_STDLIB
|
||||
#define TINYGLTF3_FREE(ptr) free(ptr)
|
||||
#else
|
||||
#define TINYGLTF3_FREE(ptr) ((void)(ptr))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ======================================================================
|
||||
* Section 4: Constants and Enums
|
||||
@@ -418,6 +448,7 @@ typedef struct tg3_asset {
|
||||
/* --- Buffer --- */
|
||||
typedef struct tg3_buffer {
|
||||
tg3_str name;
|
||||
uint64_t byte_length; /* Declared buffer.byteLength */
|
||||
tg3_span_u8 data;
|
||||
tg3_str uri;
|
||||
tg3_extras_ext ext;
|
||||
@@ -941,6 +972,10 @@ typedef struct tg3_parse_options {
|
||||
int32_t images_as_is; /* 1 = don't decode images */
|
||||
int32_t preserve_image_channels; /* 1 = keep original channels */
|
||||
int32_t store_original_json; /* 1 = store raw JSON strings */
|
||||
int32_t skip_extras_values; /* 1 = skip materializing extras and
|
||||
* unknown extension value trees */
|
||||
int32_t borrow_input_buffers; /* 1 = GLB BIN buffer spans may point
|
||||
* into caller-owned input data */
|
||||
int32_t parse_float32; /* 1 = parse JSON floats as float32 for speed
|
||||
* (breaks strict double-precision conformance
|
||||
* but sufficient for glTF data which is
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user