diff --git a/.gitignore b/.gitignore index 89fe66c1f..b30e5d592 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,15 @@ test/gtest/src/gtest-stamp/gtest-gitclone-lastrun.txt Assimp.opensdf contrib/zlib/CTestTestfile.cmake ipch/assimp_viewer-44bbbcd1/assimp_viewerd-ccc45335.ipch +bin64/assimp-vc140-mt.dll +bin64/assimp-vc140-mtd.dll +lib64/assimp-vc140-mt.exp +lib64/assimp-vc140-mtd.exp +lib64/assimp-vc140-mtd.ilk +lib64/assimp-vc140-mtd.pdb +bin64/assimp-vc120-mt.dll +bin64/assimp-vc120-mtd.dll +lib64/assimp-vc120-mtd.pdb +lib64/assimp-vc120-mtd.ilk +lib64/assimp-vc120-mtd.exp +lib64/assimp-vc120-mt.exp diff --git a/.travis.sh b/.travis.sh index aa53a64e7..7534c3f79 100755 --- a/.travis.sh +++ b/.travis.sh @@ -3,7 +3,7 @@ function generate() cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -DBUILD_SHARED_LIBS=$SHARED_BUILD } -if [ $ANDROID ]; then +if [ $ANDROID ]; then ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni else generate \ @@ -11,6 +11,6 @@ else && sudo make install \ && sudo ldconfig \ && (cd test/unit; ../../bin/unit) \ - && (cd test/regression; chmod 755 run.py; ./run.py; \ - chmod 755 result_checker.py; ./result_checker.py) + #&& (cd test/regression; chmod 755 run.py; ./run.py; \ + #chmod 755 result_checker.py; ./result_checker.py) fi diff --git a/CHANGES b/CHANGES index b26103bf2..0ff79cbe1 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,24 @@ CHANGELOG ---------------------------------------------------------------------- +3.2.0 (2015-11-03) + +FEATURES: + - OpenDDL-Parser is part of contrib-source. + - Experimental OpenGEX-support + - CI-check for linux and windows + - Coverity check added + - New regression testsuite. + +FIXES/HOUSEKEEPING: + - Hundreds of bugfixes in all parts of the library + - Unified line endings + + +API COMPATIBILITY: + - Removed precompiled header to increase build speed for linux + + 3.1.1 (2014-06-15) FEATURES: @@ -18,18 +36,18 @@ FEATURES: FIXES/HOUSEKEEPING: - Hundreds of bugfixes in all parts of the library - CMake is now the primary build system - + API COMPATIBILITY: - 3.1.1 is not binary compatible to 3.0 due to aiNode::mMetaData and aiMesh::mName - Export interface has been cleaned up and unified - Other than that no relevant changes - + 3.0 (2012-07-07) FEATURES: - - new export interface similar to the import API. + - new export interface similar to the import API. - Supported export formats: Collada, OBJ, PLY and STL - added new import formats: XGL/ZGL, M3 (experimental) - new postprocessing steps: Debone @@ -46,11 +64,11 @@ FIXES/HOUSEKEEPING: - improved CMake build system - templatized math library - reduce dependency on boost.thread, only remaining spot - is synchronization for the C logging API + is synchronization for the C logging API API COMPATIBILITY: - renamed headers, export interface, C API properties and meta data - prevent compatibility with code written for 2.0, but in + prevent compatibility with code written for 2.0, but in most cases these can be easily resolved - Note: 3.0 is not binary compatible with 2.0 @@ -68,9 +86,9 @@ FEATURES: spatial structure) in some expensive postprocessing steps - AssimpView now uses a reworked layout which leaves more space to the scene hierarchy window - + - Add C# bindings ('Assimp.NET') - - Keep BSD-licensed and otherwise free test files in separate + - Keep BSD-licensed and otherwise free test files in separate folders (./test/models and ./test/models-nonbsd). FIXES: @@ -80,20 +98,20 @@ FIXES: - OpenGL-sample now works with MinGW - Fix Importer::FindLoader failing on uppercase file extensions - Fix flawed path handling when locating external files - - Limit the maximum number of vertices, faces, face indices and + - Limit the maximum number of vertices, faces, face indices and weights that Assimp is able to handle. This is to avoid crashes due to overflowing counters. - + - Updated XCode project files - Further CMAKE build improvements - + API CHANGES: - Add data structures for vertex-based animations (These are not currently used, however ...) - Some Assimp::Importer methods are const now. - - + + diff --git a/CMakeLists.txt b/CMakeLists.txt index cbb7bd641..8434e4628 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ endif(NOT BUILD_SHARED_LIBS) # Define here the needed parameters set (ASSIMP_VERSION_MAJOR 3) -set (ASSIMP_VERSION_MINOR 1) -set (ASSIMP_VERSION_PATCH 1) # subversion revision? +set (ASSIMP_VERSION_MINOR 2) +set (ASSIMP_VERSION_PATCH 0) # subversion revision? set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}) set (ASSIMP_SOVERSION 3) set (PROJECT_VERSION "${ASSIMP_VERSION}") @@ -98,10 +98,10 @@ SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH "Path the tool executables are installed to." ) -IF (CMAKE_BUILD_TYPE STREQUAL "Release") - SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") -ELSE() +IF (CMAKE_BUILD_TYPE STREQUAL "Debug") SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") +ELSE() + SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") ENDIF() # Only generate this target if no higher-level project already has @@ -340,3 +340,31 @@ if(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) include(CPack) include(DebSourcePPA) endif() + +if(WIN32) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/") + set(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/") + elseif() + set(BIN_DIR "${PROJECT_SOURCE_DIR}/bin32/") + set(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/") + endif() + + if(MSVC12) + set(ASSIMP_MSVC_VERSION "vc120") + elseif(MSVC14) + set(ASSIMP_MSVC_VERSION "vc140") + endif(MSVC12) + + if(MSVC12 OR MSVC14) + add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM) + add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) + endif(MSVC12 OR MSVC14) +endif (WIN32) \ No newline at end of file diff --git a/INSTALL b/INSTALL index 563fda397..3baaddc4a 100644 --- a/INSTALL +++ b/INSTALL @@ -33,13 +33,12 @@ CMake is the preferred build system for Assimp. The minimum required version is 2.6. If you don't have it yet, downloads for CMake can be found on http://www.cmake.org/. -Building Assimp with CMake is 'business as usual' if you've used CMake -before. All steps can be done either on the command line / shell or -by using the CMake GUI tool, the choice is up to you. - -First, invoke CMake to generate build files for a particular -toolchain (for standard GNU makefiles: cmake -G 'Unix Makefiles'). -Afterwards, use the generated build files to perform the actual -build. +For Unix: +1. cmake CMakeLists.txt -G 'Unix Makefiles' +2. make +For Windows: +1. Open a command prompt +2. cmake CMakeLists.txt +2. Open your default IDE and build it diff --git a/LICENSE b/LICENSE index e6617569d..c8e47b34a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,10 +1,10 @@ Open Asset Import Library (assimp) -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -21,16 +21,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +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 +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 +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 +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. @@ -41,9 +41,9 @@ AN EXCEPTION applies to all files in the ./test/models-nonbsd folder. These are 3d models for testing purposes, from various free sources on the internet. They are - unless otherwise stated - copyright of their respective creators, which may impose additional requirements -on the use of their work. For any of these models, see +on the use of their work. For any of these models, see .source.txt for more legal information. Contact us if you -are a copyright holder and believe that we credited you inproperly or +are a copyright holder and believe that we credited you inproperly or if you don't want your files to appear in the repository. @@ -76,9 +76,3 @@ 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. - - - - - - diff --git a/Readme.md b/Readme.md index 1a99bf873..0564e4eda 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,5 @@ -Open Asset Import Library (assimp) -======== - +Open Asset Import Library (assimp) +================================== Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export. APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. @@ -28,28 +27,28 @@ __Importers__: - BLEND (Blender) - DAE/Collada - FBX -- IFC-STEP +- IFC-STEP - ASE - DXF - HMP - MD2 -- MD3 +- MD3 - MD5 - MDC - MDL - NFF - PLY - STL -- X +- X - OBJ - OpenGEX - SMD -- LWO -- LXO +- LWO +- LXO - LWS -- TER -- AC3D -- MS3D +- TER +- AC3D +- MS3D - COB - Q3BSP - XGL @@ -61,7 +60,8 @@ __Importers__: - Ogre XML - Q3D - ASSBIN (Assimp custom format) - +- glTF + Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): - C4D (https://github.com/acgessler/assimp-cinema4d) @@ -76,16 +76,18 @@ __Exporters__: - 3DS - JSON (for WebGl, via https://github.com/acgessler/assimp2json) - ASSBIN - +- glTF + ### Building ### - - Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do. +### Ports ### +* [Android](port/AndroidJNI/README.md) +* [Python](port/PyAssimp/README.md) +* [.NET](port/AssimpNET/Readme.md) +* [Pascal](port/AssimpPascal/Readme.md) #### Repository structure #### - - Open Asset Import Library is implemented in C++. The directory structure is: /code Source code @@ -96,35 +98,34 @@ Open Asset Import Library is implemented in C++. The directory structure is: /port Ports to other languages and scripts to maintain those. /test Unit- and regression tests, test suite of models /tools Tools (old assimp viewer, command line `assimp`) - /samples A small number of samples to illustrate possible + /samples A small number of samples to illustrate possible use cases for Assimp /workspaces Build enviroments for vc,xcode,... (deprecated, CMake has superseeded all legacy build options!) ### Where to get help ### - - For more information, visit [our website](http://assimp.sourceforge.net/). Or check out the `./doc`- folder, which contains the official documentation in HTML format. (CHMs for Windows are included in some release packages and should be located right here in the root folder). If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github. For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_ - [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) + [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type > /join #assetimporterlib ### Contributing ### - -Contributions to assimp are highly appreciated. The easiest way to get involved is to submit +Contributions to assimp are highly appreciated. The easiest way to get involved is to submit a pull request with your changes against the main repository's `master` branch. ### License ### +Our license is based on the modified, __3-clause BSD__-License. -Our license is based on the modified, __3-clause BSD__-License. - -An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - +An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp. -For the legal details, see the `LICENSE` file. +For the legal details, see the `LICENSE` file. + +### Why this name ### +Sorry, we're germans :-), no english native speakers ... diff --git a/appveyor.yml b/appveyor.yml index 8c3264cbf..41e483d80 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,12 +10,31 @@ branches: only: - master -platform: x64 -configuration: Release +platform: + - x86 + - x64 -build: +configuration: + - 14 2015 + - 12 2013 + #- MinGW + - 10 2010 # only works for x86 + +init: +- if "%platform%" EQU "x64" ( for %%a in (2008 2010 MinGW) do ( if "%Configuration%"=="%%a" (echo "Skipping unsupported configuration" && exit /b 1 ) ) ) + +install: +# Make compiler command line tools available +- call c:\projects\assimp\scripts\appveyor\compiler_setup.bat build_script: - cd c:\projects\assimp - - cmake CMakeLists.txt -G "Visual Studio 11" + - cmake CMakeLists.txt -G "Visual Studio %Configuration%" - msbuild /m /p:Configuration=Release /p:Platform="Win32" Assimp.sln + +after_build: + - 7z a assimp.7z c:\projects\assimp\bin\release\* c:\projects\assimp\lib\release\* + +artifacts: + - path: assimp.7z + name: assimp_lib diff --git a/assimp-config.cmake.in b/assimp-config.cmake.in index 098eba85b..7e57d79d3 100644 --- a/assimp-config.cmake.in +++ b/assimp-config.cmake.in @@ -29,8 +29,10 @@ if( MSVC ) set(MSVC_PREFIX "vc110") elseif( MSVC12 ) set(MSVC_PREFIX "vc120") + elseif( MSVC14 ) + set(MSVC_PREFIX "vc140") else() - set(MSVC_PREFIX "vc130") + set(MSVC_PREFIX "vc150") endif() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE) else() diff --git a/cmake-modules/AddGTest.cmake b/cmake-modules/AddGTest.cmake index 1ffd36a10..275587600 100644 --- a/cmake-modules/AddGTest.cmake +++ b/cmake-modules/AddGTest.cmake @@ -10,6 +10,9 @@ endif() if (MSVC) set(RELEASE_LIB_DIR ReleaseLibs) set(DEBUG_LIB_DIR DebugLibs) +elseif(XCODE_VERSION) + set(RELEASE_LIB_DIR Release) + set(DEBUG_LIB_DIR Debug) else() set(RELEASE_LIB_DIR "") set(DEBUG_LIB_DIR "") @@ -18,7 +21,8 @@ endif() set(GTEST_CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "-Dgtest_force_shared_crt=ON" - "-Dgtest_disable_pthreads:BOOL=${DISABLE_PTHREADS}") + "-Dgtest_disable_pthreads:BOOL=${DISABLE_PTHREADS}" + "-DBUILD_GTEST=ON") set(GTEST_RELEASE_LIB_DIR "") set(GTEST_DEBUGLIB_DIR "") if (MSVC) @@ -38,7 +42,7 @@ else(NOT GIT_FOUND) set(AddGTest_FOUND true CACHE BOOL "Was gtest setup correctly?") ExternalProject_Add(gtest - GIT_REPOSITORY https://chromium.googlesource.com/external/googletest + GIT_REPOSITORY https://github.com/google/googletest.git TIMEOUT 10 PREFIX "${GTEST_PREFIX}" CMAKE_ARGS "${GTEST_CMAKE_ARGS}" @@ -53,10 +57,10 @@ else(NOT GIT_FOUND) set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}") set(GTEST_LOCATION "${GTEST_PREFIX}/src/gtest-build") set(GTEST_DEBUG_LIBRARIES - "${GTEST_LOCATION}/${DEBUG_LIB_DIR}/${LIB_PREFIX}gtest${LIB_SUFFIX}" + "${LIB_PREFIX}gtest${LIB_SUFFIX}" "${CMAKE_THREAD_LIBS_INIT}") SET(GTEST_RELEASE_LIBRARIES - "${GTEST_LOCATION}/${RELEASE_LIB_DIR}/${LIB_PREFIX}gtest${LIB_SUFFIX}" + "${LIB_PREFIX}gtest${LIB_SUFFIX}" "${CMAKE_THREAD_LIBS_INIT}") if(MSVC_VERSION EQUAL 1700) @@ -64,9 +68,11 @@ else(NOT GIT_FOUND) endif() ExternalProject_Get_Property(gtest source_dir) - include_directories(${source_dir}/include) + include_directories(${source_dir}/googletest/include) include_directories(${source_dir}/gtest/include) ExternalProject_Get_Property(gtest binary_dir) - link_directories(${binary_dir}) + link_directories(${binary_dir}/googlemock/gtest) + link_directories(${binary_dir}/googlemock/gtest/${RELEASE_LIB_DIR}) + link_directories(${binary_dir}/googlemock/gtest/${DEBUG_LIB_DIR}) endif(NOT GIT_FOUND) diff --git a/cmake-modules/FindPkgMacros.cmake b/cmake-modules/FindPkgMacros.cmake index facd5946b..e67d8dc62 100644 --- a/cmake-modules/FindPkgMacros.cmake +++ b/cmake-modules/FindPkgMacros.cmake @@ -85,7 +85,7 @@ macro(get_debug_names PREFIX) endforeach(i) endmacro(get_debug_names) -# Add the parent dir from DIR to VAR +# Add the parent dir from DIR to VAR macro(add_parent_dir VAR DIR) get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) set(${VAR} ${${VAR}} ${${DIR}_TEMP}) @@ -127,6 +127,7 @@ MACRO(findpkg_framework fwk) /System/Library/Frameworks /Network/Library/Frameworks /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/ + /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/ ) FOREACH(dir ${${fwk}_FRAMEWORK_PATH}) SET(fwkpath ${dir}/${fwk}.framework) diff --git a/cmake-modules/Findassimp.cmake b/cmake-modules/Findassimp.cmake index 971b49d5e..95f3250b3 100644 --- a/cmake-modules/Findassimp.cmake +++ b/cmake-modules/Findassimp.cmake @@ -1,25 +1,81 @@ -FIND_PATH( - assimp_INCLUDE_DIRS - NAMES postprocess.h scene.h version.h config.h cimport.h - PATHS /usr/local/include/ -) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ASSIMP_ARCHITECTURE "64") +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(ASSIMP_ARCHITECTURE "32") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + +if(WIN32) + set(ASSIMP_ROOT_DIR CACHE PATH "ASSIMP root directory") -FIND_LIBRARY( - assimp_LIBRARIES - NAMES assimp - PATHS /usr/local/lib/ -) + # Find path of each library + find_path(ASSIMP_INCLUDE_DIR + NAMES + assimp/anim.h + HINTS + ${ASSIMP_ROOT_DIR}/include + ) -IF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) - SET(assimp_FOUND TRUE) -ENDIF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) + if(MSVC12) + set(ASSIMP_MSVC_VERSION "vc120") + elseif(MSVC14) + set(ASSIMP_MSVC_VERSION "vc140") + endif(MSVC12) + + if(MSVC12 OR MSVC14) + + find_path(ASSIMP_LIBRARY_DIR + NAMES + assimp-${ASSIMP_MSVC_VERSION}-mt.lib + HINTS + ${ASSIMP_ROOT_DIR}/lib${ASSIMP_ARCHITECTURE} + ) + + find_library(ASSIMP_LIBRARY_RELEASE assimp-${ASSIMP_MSVC_VERSION}-mt.lib PATHS ${ASSIMP_LIBRARY_DIR}) + find_library(ASSIMP_LIBRARY_DEBUG assimp-${ASSIMP_MSVC_VERSION}-mtd.lib PATHS ${ASSIMP_LIBRARY_DIR}) + + set(ASSIMP_LIBRARY + optimized ${ASSIMP_LIBRARY_RELEASE} + debug ${ASSIMP_LIBRARY_DEBUG} + ) + + set(ASSIMP_LIBRARIES "ASSIMP_LIBRARY_RELEASE" "ASSIMP_LIBRARY_DEBUG") + + FUNCTION(ASSIMP_COPY_BINARIES TargetDirectory) + ADD_CUSTOM_TARGET(AssimpCopyBinaries + COMMAND ${CMAKE_COMMAND} -E copy ${ASSIMP_ROOT_DIR}/bin${ASSIMP_ARCHITECTURE}/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${TargetDirectory}/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll + COMMAND ${CMAKE_COMMAND} -E copy ${ASSIMP_ROOT_DIR}/bin${ASSIMP_ARCHITECTURE}/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${TargetDirectory}/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll + COMMENT "Copying Assimp binaries to '${TargetDirectory}'" + VERBATIM) + ENDFUNCTION(ASSIMP_COPY_BINARIES) + + endif() + +else(WIN32) -IF (assimp_FOUND) - IF (NOT assimp_FIND_QUIETLY) - MESSAGE(STATUS "Found asset importer library: ${assimp_LIBRARIES}") - ENDIF (NOT assimp_FIND_QUIETLY) -ELSE (assimp_FOUND) - IF (assimp_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find asset importer library") - ENDIF (assimp_FIND_REQUIRED) -ENDIF (assimp_FOUND) + find_path( + assimp_INCLUDE_DIRS + NAMES postprocess.h scene.h version.h config.h cimport.h + PATHS /usr/local/include/ + ) + + find_library( + assimp_LIBRARIES + NAMES assimp + PATHS /usr/local/lib/ + ) + + if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) + SET(assimp_FOUND TRUE) + ENDIF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) + + if (assimp_FOUND) + if (NOT assimp_FIND_QUIETLY) + message(STATUS "Found asset importer library: ${assimp_LIBRARIES}") + endif (NOT assimp_FIND_QUIETLY) + else (assimp_FOUND) + if (assimp_FIND_REQUIRED) + message(FATAL_ERROR "Could not find asset importer library") + endif (assimp_FIND_REQUIRED) + endif (assimp_FOUND) + +endif(WIN32) \ No newline at end of file diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 08dd5ce49..cea255380 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -70,8 +70,9 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() for (unsigned int i = 0; i < mScene->mMaterials.size();++i) { std::string s = mScene->mMaterials[i].mName; - for (std::string::iterator it = s.begin(); it != s.end(); ++it) - *it = ::tolower(*it); + for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) { + *it = static_cast< char >( ::tolower( *it ) ); + } if (std::string::npos == s.find("default"))continue; @@ -663,14 +664,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; // Rotations are quaternion offsets - aiQuaternion abs; + aiQuaternion abs1; for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) { const aiQuatKey& q = pcIn->aRotationKeys[n]; - abs = (n ? abs * q.mValue : q.mValue); + abs1 = (n ? abs1 * q.mValue : q.mValue); nda->mRotationKeys[n].mTime = q.mTime; - nda->mRotationKeys[n].mValue = abs.Normalize(); + nda->mRotationKeys[n].mValue = abs1.Normalize(); } } @@ -757,7 +758,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) pcNode->mNumMeshes = 1; // Build a name for the node - pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%u",i); + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i); } // Build dummy nodes for all cameras diff --git a/code/3DSExporter.cpp b/code/3DSExporter.cpp index 324dc2235..f33799fef 100644 --- a/code/3DSExporter.cpp +++ b/code/3DSExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/3DSExporter.h b/code/3DSExporter.h index 97ebf003e..ce9a02f78 100644 --- a/code/3DSExporter.h +++ b/code/3DSExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/3DSHelper.h b/code/3DSHelper.h index b30cb4914..5911b9d47 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SpatialSort.h" #include "SmoothingGroups.h" +#include "StringUtils.h" #include "qnan.h" #include "./../include/assimp/material.h" #include "./../include/assimp/camera.h" @@ -379,7 +380,7 @@ struct Material static int iCnt = 0; char szTemp[128]; - sprintf(szTemp,"UNNAMED_%i",iCnt++); + ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); mName = szTemp; } @@ -435,7 +436,7 @@ struct Mesh : public MeshWithSmoothingGroups // Generate a default name for the mesh char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); + ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); mName = szTemp; } @@ -484,18 +485,18 @@ struct aiFloatKey /** Helper structure to represent a 3ds file node */ struct Node { - Node() - : mParent() - , mInstanceNumber() - , mHierarchyPos (0) - , mHierarchyIndex (0) - , mInstanceCount (1) + Node(): + mParent(NULL) + , mInstanceNumber(0) + , mHierarchyPos (0) + , mHierarchyIndex (0) + , mInstanceCount (1) { static int iCnt = 0; // Generate a default name for the node char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); mName = szTemp; aRotationKeys.reserve (20); diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index 3c80c320b..2c55ba977 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -86,8 +86,8 @@ static const aiImporterDesc desc = { int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ if(chunkSize <= 0) \ continue; \ - const int oldReadLimit = stream->GetReadLimit(); \ - stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); \ + const unsigned int oldReadLimit = stream->SetReadLimit( \ + stream->GetCurrentPos() + chunkSize); \ // ------------------------------------------------------------------------------------------------ diff --git a/code/3DSLoader.h b/code/3DSLoader.h index 5d30a9106..134f4012b 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ACLoader.cpp b/code/ACLoader.cpp index 8e62da442..f84027501 100644 --- a/code/ACLoader.cpp +++ b/code/ACLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -211,7 +211,7 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) // Generate a default name for both the light source and the node // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. - light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast(mLights->size())-1); + light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast(mLights->size())-1); obj.name = std::string( light->mName.data ); DefaultLogger::get()->debug("AC3D: Light source encountered"); @@ -733,18 +733,18 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, switch (object.type) { case Object::Group: - node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++); + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++); break; case Object::Poly: - node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++); + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i",polys++); break; case Object::Light: - node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++); + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i",lights++); break; // there shouldn't be more than one world, but we don't care case Object::World: - node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++); + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i",worlds++); break; } } diff --git a/code/ACLoader.h b/code/ACLoader.h index 57c48a823..7ea336666 100644 --- a/code/ACLoader.h +++ b/code/ACLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 395a4e4ca..514b6b66c 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/ASELoader.h b/code/ASELoader.h index a200b9f08..e0cd55d49 100644 --- a/code/ASELoader.h +++ b/code/ASELoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index f37e7bd48..37b7ea0cd 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -143,9 +143,9 @@ void Parser::LogWarning(const char* szWarn) char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); + sprintf_s(szTemp, "Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif // output the warning to the logger ... @@ -161,7 +161,7 @@ void Parser::LogInfo(const char* szWarn) #if _MSC_VER >= 1400 sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif // output the information to the logger ... @@ -177,7 +177,7 @@ AI_WONT_RETURN void Parser::LogError(const char* szWarn) #if _MSC_VER >= 1400 sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif // throw an exception @@ -825,7 +825,7 @@ bool Parser::ParseString(std::string& out,const char* szName) if (!SkipSpaces(&filePtr)) { - sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName); + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL",szName); LogWarning(szBuffer); return false; } @@ -833,7 +833,7 @@ bool Parser::ParseString(std::string& out,const char* szName) if ('\"' != *filePtr) { - sprintf(szBuffer,"Unable to parse %s block: Strings are expected " + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected " "to be enclosed in double quotation marks",szName); LogWarning(szBuffer); return false; @@ -845,7 +845,7 @@ bool Parser::ParseString(std::string& out,const char* szName) if ('\"' == *sz)break; else if ('\0' == *sz) { - sprintf(szBuffer,"Unable to parse %s block: Strings are expected to " + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected to " "be enclosed in double quotation marks but EOF was reached before " "a closing quotation mark was encountered",szName); LogWarning(szBuffer); @@ -1134,7 +1134,7 @@ void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim) bool b = false; // For the moment we're just reading the three floats - - // we ignore the ádditional information for bezier's and TCBs + // we ignore the �dditional information for bezier's and TCBs // simple scaling keyframe if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20)) @@ -1180,7 +1180,7 @@ void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim) bool b = false; // For the moment we're just reading the three floats - - // we ignore the ádditional information for bezier's and TCBs + // we ignore the �dditional information for bezier's and TCBs // simple scaling keyframe if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18)) @@ -1226,7 +1226,7 @@ void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim) bool b = false; // For the moment we're just reading the floats - - // we ignore the ádditional information for bezier's and TCBs + // we ignore the �dditional information for bezier's and TCBs // simple scaling keyframe if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18)) diff --git a/code/ASEParser.h b/code/ASEParser.h index e0a628606..6a3e56e71 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -133,12 +133,12 @@ struct Bone // Generate a default name for the bone char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); mName = szTemp; } //! Construction from an existing name - Bone( const std::string& name) + explicit Bone( const std::string& name) : mName (name) {} @@ -216,14 +216,14 @@ struct BaseNode enum Type {Light, Camera, Mesh, Dummy} mType; //! Constructor. Creates a default name for the node - BaseNode(Type _mType) + explicit BaseNode(Type _mType) : mType (_mType) , mProcessed (false) { // generate a default name for the node static int iCnt = 0; char szTemp[128]; // should be sufficiently large - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); mName = szTemp; // Set mTargetPosition to qnan diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp index 652405c84..9a70d7166 100644 --- a/code/AssbinExporter.cpp +++ b/code/AssbinExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -702,7 +702,7 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) #if _MSC_VER >= 1400 sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); #else - snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); + ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); #endif out->Write( s, 44, 1 ); // == 44 bytes diff --git a/code/AssbinExporter.h b/code/AssbinExporter.h index e16393213..4a0219c04 100644 --- a/code/AssbinExporter.h +++ b/code/AssbinExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssbinLoader.cpp b/code/AssbinLoader.cpp index dd949695e..509741277 100644 --- a/code/AssbinLoader.cpp +++ b/code/AssbinLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/AssbinLoader.h b/code/AssbinLoader.h index 4f2638fb8..10d4f0901 100644 --- a/code/AssbinLoader.h +++ b/code/AssbinLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Assimp.cpp b/code/Assimp.cpp index 03c39671b..d46ebe537 100644 --- a/code/Assimp.cpp +++ b/code/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -96,11 +96,13 @@ namespace Assimp /** will return all registered importers. */ void GetImporterInstanceList(std::vector< BaseImporter* >& out); + /** will delete all registered importers. */ + void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); } // namespace assimp #ifndef ASSIMP_BUILD_SINGLETHREADED -/** Global mutex to manage the access to the logstream map */ +/** Global mutex to manage the access to the log-stream map */ static boost::mutex gLogStreamMutex; #endif @@ -110,7 +112,7 @@ static boost::mutex gLogStreamMutex; class LogToCallbackRedirector : public LogStream { public: - LogToCallbackRedirector(const aiLogStream& s) + explicit LogToCallbackRedirector(const aiLogStream& s) : stream (s) { ai_assert(NULL != s.callback); } @@ -228,7 +230,8 @@ const aiScene* aiImportFileFromMemoryWithProperties( const char* pHint, const aiPropertyStore* props) { - ai_assert(NULL != pBuffer && 0 != pLength); + ai_assert( NULL != pBuffer ); + ai_assert( 0 != pLength ); const aiScene* scene = NULL; ASSIMP_BEGIN_EXCEPTION_REGION(); @@ -317,10 +320,38 @@ ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, return sc; } +// ------------------------------------------------------------------------------------------------ +ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene, + BaseProcess* process, + bool requestValidation ) { + const aiScene* sc( NULL ); + + ASSIMP_BEGIN_EXCEPTION_REGION(); + + // find the importer associated with this data + const ScenePrivateData* priv = ScenePriv( scene ); + if ( NULL == priv || NULL == priv->mOrigImporter ) { + ReportSceneNotFoundError(); + return NULL; + } + + sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation ); + + if ( !sc ) { + aiReleaseImport( scene ); + return NULL; + } + + ASSIMP_END_EXCEPTION_REGION( const aiScene* ); + + return sc; +} + // ------------------------------------------------------------------------------------------------ void CallbackToLogRedirector (const char* msg, char* dt) { - ai_assert(NULL != msg && NULL != dt); + ai_assert( NULL != msg ); + ai_assert( NULL != dt ); LogStream* s = (LogStream*)dt; s->write(msg); @@ -373,7 +404,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) #ifndef ASSIMP_BUILD_SINGLETHREADED boost::mutex::scoped_lock lock(gLogStreamMutex); #endif - // find the logstream associated with this data + // find the log-stream associated with this data LogStreamMap::iterator it = gActiveLogStreams.find( *stream); // it should be there... else the user is playing fools with us if( it == gActiveLogStreams.end()) { @@ -398,12 +429,18 @@ ASSIMP_API void aiDetachAllLogStreams(void) #ifndef ASSIMP_BUILD_SINGLETHREADED boost::mutex::scoped_lock lock(gLogStreamMutex); #endif + Logger *logger( DefaultLogger::get() ); + if ( NULL == logger ) { + return; + } + for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { - DefaultLogger::get()->detatchStream( it->second ); + logger->detatchStream( it->second ); delete it->second; } gActiveLogStreams.clear(); DefaultLogger::kill(); + ASSIMP_END_EXCEPTION_REGION(void); } @@ -437,7 +474,6 @@ size_t aiGetImportFormatCount(void) return Importer().GetImporterCount(); } - // ------------------------------------------------------------------------------------------------ // Returns the error text of the last failed import process. aiBool aiIsExtensionSupported(const char* szExtension) @@ -492,7 +528,6 @@ ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) return reinterpret_cast( new PropertyMap() ); } - // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) { @@ -551,7 +586,8 @@ ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName // Rotation matrix to quaternion ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) { - ai_assert(NULL != quat && NULL != mat); + ai_assert( NULL != quat ); + ai_assert( NULL != mat ); *quat = aiQuaternion(*mat); } @@ -561,7 +597,10 @@ ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, aiQuaternion* rotation, aiVector3D* position) { - ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat); + ai_assert( NULL != rotation ); + ai_assert( NULL != position ); + ai_assert( NULL != scaling ); + ai_assert( NULL != mat ); mat->Decompose(*scaling,*rotation,*position); } @@ -585,7 +624,8 @@ ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, const aiMatrix3x3* mat) { - ai_assert(NULL != mat && NULL != vec); + ai_assert( NULL != mat ); + ai_assert( NULL != vec); *vec *= (*mat); } @@ -593,7 +633,9 @@ ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, const aiMatrix4x4* mat) { - ai_assert(NULL != mat && NULL != vec); + ai_assert( NULL != mat ); + ai_assert( NULL != vec ); + *vec *= (*mat); } @@ -603,7 +645,8 @@ ASSIMP_API void aiMultiplyMatrix4( aiMatrix4x4* dst, const aiMatrix4x4* src) { - ai_assert(NULL != dst && NULL != src); + ai_assert( NULL != dst ); + ai_assert( NULL != src ); *dst = (*dst) * (*src); } @@ -612,7 +655,8 @@ ASSIMP_API void aiMultiplyMatrix3( aiMatrix3x3* dst, const aiMatrix3x3* src) { - ai_assert(NULL != dst && NULL != src); + ai_assert( NULL != dst ); + ai_assert( NULL != src ); *dst = (*dst) * (*src); } @@ -648,6 +692,8 @@ ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extensi } } + DeleteImporterInstanceList(out); + return desc; } diff --git a/code/AssimpCExport.cpp b/code/AssimpCExport.cpp index 6578eeb88..c8c8fc107 100644 --- a/code/AssimpCExport.cpp +++ b/code/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -59,13 +59,38 @@ ASSIMP_API size_t aiGetExportFormatCount(void) // ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex) +ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index) { - // Note: this is valid as the index always pertains to a builtin exporter, + // Note: this is valid as the index always pertains to a built-in exporter, // for which the returned structure is guaranteed to be of static storage duration. - return Exporter().GetExportFormatDescription(pIndex); + Exporter exporter; + const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) ); + if (NULL == orig) { + return NULL; + } + + aiExportFormatDesc *desc = new aiExportFormatDesc; + desc->description = new char[ strlen( orig->description ) + 1 ]; + ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) ); + desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ]; + ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) ); + desc->id = new char[ strlen( orig->id ) + 1 ]; + ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) ); + + return desc; } +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) { + if (NULL == desc) { + return; + } + + delete [] desc->description; + delete [] desc->fileExtension; + delete [] desc->id; + delete desc; +} // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut) diff --git a/code/AssxmlExporter.cpp b/code/AssxmlExporter.cpp index f1b6a2232..669ff64ca 100644 --- a/code/AssxmlExporter.cpp +++ b/code/AssxmlExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -70,8 +70,8 @@ int ioprintf( IOStream * io, const char * format, ... ) char sz[4096]; va_list va; va_start( va, format ); - int nSize = vsnprintf( sz, 4096, format, va ); - ai_assert( nSize < 4096 ); + int nSize = ai_snprintf( sz, 4096, format, va ); + ai_assert( nSize < 4096 ); va_end( va ); io->Write( sz, sizeof(char), nSize ); diff --git a/code/AssxmlExporter.h b/code/AssxmlExporter.h index 37a91242a..ba9921f70 100644 --- a/code/AssxmlExporter.h +++ b/code/AssxmlExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/B3DImporter.cpp b/code/B3DImporter.cpp index 4e6b18941..05109cacb 100644 --- a/code/B3DImporter.cpp +++ b/code/B3DImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "B3DImporter.h" #include "TextureTransform.h" #include "ConvertToLHProcess.h" +#include "StringUtils.h" #include #include "../include/assimp/IOSystem.hpp" #include "../include/assimp/anim.h" @@ -571,7 +572,7 @@ void B3DImporter::ReadBB3D( aiScene *scene ){ if (!DefaultLogger::isNullLogger()) { char dmp[128]; - sprintf(dmp,"B3D file format version: %i",version); + ai_snprintf(dmp, 128, "B3D file format version: %i",version); DefaultLogger::get()->info(dmp); } diff --git a/code/B3DImporter.h b/code/B3DImporter.h index 9581c3469..964ea46d6 100644 --- a/code/B3DImporter.h +++ b/code/B3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BVHLoader.cpp b/code/BVHLoader.cpp index fd2273adf..1f4bc2e71 100644 --- a/code/BVHLoader.cpp +++ b/code/BVHLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/BVHLoader.h b/code/BVHLoader.h index 8c88484f6..8a163d1e7 100644 --- a/code/BVHLoader.h +++ b/code/BVHLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -83,7 +83,7 @@ class BVHLoader : public BaseImporter std::vector mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames Node() { } - Node( const aiNode* pNode) : mNode( pNode) { } + explicit Node( const aiNode* pNode) : mNode( pNode) { } }; public: diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 303c06779..d58c30b2f 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -435,22 +435,27 @@ void BaseImporter::ConvertUTF8toISO8859_1(std::string& data) // ------------------------------------------------------------------------------------------------ void BaseImporter::TextFileToBuffer(IOStream* stream, - std::vector& data) + std::vector& data, + TextFileMode mode) { ai_assert(NULL != stream); const size_t fileSize = stream->FileSize(); - if(!fileSize) { - throw DeadlyImportError("File is empty"); + if (mode == FORBID_EMPTY) { + if(!fileSize) { + throw DeadlyImportError("File is empty"); + } } data.reserve(fileSize+1); data.resize(fileSize); - if(fileSize != stream->Read( &data[0], 1, fileSize)) { - throw DeadlyImportError("File read error"); - } + if(fileSize > 0) { + if(fileSize != stream->Read( &data[0], 1, fileSize)) { + throw DeadlyImportError("File read error"); + } - ConvertToUTF8(data); + ConvertToUTF8(data); + } // append a binary zero to simplify string parsing data.push_back(0); diff --git a/code/BaseImporter.h b/code/BaseImporter.h index e8ed7460d..75e1fdb00 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -70,7 +70,7 @@ class IOStream; template struct ScopeGuard { - ScopeGuard(T* obj) : obj(obj), mdismiss() {} + explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {} ~ScopeGuard () throw() { if (!mdismiss) { delete obj; @@ -347,6 +347,8 @@ public: // static utilities static void ConvertUTF8toISO8859_1( std::string& data); + enum TextFileMode { ALLOW_EMPTY, FORBID_EMPTY }; + // ------------------------------------------------------------------- /** Utility for text file loaders which copies the contents of the * file into a memory buffer and converts it to our UTF8 @@ -354,10 +356,33 @@ public: // static utilities * @param stream Stream to read from. * @param data Output buffer to be resized and filled with the * converted text file data. The buffer is terminated with - * a binary 0. */ + * a binary 0. + * @param mode Whether it is OK to load empty text files. */ static void TextFileToBuffer( IOStream* stream, - std::vector& data); + std::vector& data, + TextFileMode mode = FORBID_EMPTY); + + // ------------------------------------------------------------------- + /** Utility function to move a std::vector into a aiScene array + * @param vec The vector to be moved + * @param out The output pointer to the allocated array. + * @param numOut The output count of elements copied. */ + template + AI_FORCE_INLINE + static void CopyVector( + std::vector& vec, + T*& out, + unsigned int& outLength) + { + outLength = vec.size(); + if (outLength) { + out = new T[outLength]; + std::swap_ranges(vec.begin(), vec.end(), out); + } + } + + protected: diff --git a/code/BaseProcess.cpp b/code/BaseProcess.cpp index 199f13caa..f0fb55e2b 100644 --- a/code/BaseProcess.cpp +++ b/code/BaseProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/BaseProcess.h b/code/BaseProcess.h index 0e7530f16..ec4ba3e4f 100644 --- a/code/BaseProcess.h +++ b/code/BaseProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -74,7 +74,7 @@ public: template struct THeapData : public Base { - THeapData(T* in) + explicit THeapData(T* in) : data (in) {} @@ -89,7 +89,7 @@ public: template struct TStaticData : public Base { - TStaticData(T in) + explicit TStaticData(T in) : data (in) {} diff --git a/code/Bitmap.cpp b/code/Bitmap.cpp index 13ec37204..7611a45e8 100644 --- a/code/Bitmap.cpp +++ b/code/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -84,7 +84,12 @@ namespace Assimp { template inline std::size_t Copy(uint8_t* data, T& field) { +#ifdef AI_BUILD_BIG_ENDIAN + T field_swapped=AI_BE(field); + std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field); +#else std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); +#endif } void Bitmap::WriteHeader(Header& header, IOStream* file) { diff --git a/code/Bitmap.h b/code/Bitmap.h index 6fe275cc1..ad29783ce 100644 --- a/code/Bitmap.h +++ b/code/Bitmap.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/BlenderDNA.cpp b/code/BlenderDNA.cpp index 45797b3ef..5fb14c052 100644 --- a/code/BlenderDNA.cpp +++ b/code/BlenderDNA.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderDNA.h b/code/BlenderDNA.h index 55eafdc77..98095391b 100644 --- a/code/BlenderDNA.h +++ b/code/BlenderDNA.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderDNA.inl b/code/BlenderDNA.inl index d3f8224a9..f23d723ee 100644 --- a/code/BlenderDNA.inl +++ b/code/BlenderDNA.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderIntermediate.h b/code/BlenderIntermediate.h index 7f9fffd99..bf332516e 100644 --- a/code/BlenderIntermediate.h +++ b/code/BlenderIntermediate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderLoader.cpp b/code/BlenderLoader.cpp index de980802a..abf6bb9c0 100644 --- a/code/BlenderLoader.cpp +++ b/code/BlenderLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BlenderIntermediate.h" #include "BlenderModifier.h" #include "BlenderBMesh.h" +#include "StringUtils.h" #include "../include/assimp/scene.h" #include "StringComparison.h" @@ -496,7 +497,7 @@ void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, c (void)mat; (void)tex; (void)conv_data; aiString name; - name.length = sprintf(name.data, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++, + name.length = ai_snprintf(name.data, MAXLEN, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++, GetTextureTypeDisplayString(tex->tex->type) ); out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE( @@ -1010,13 +1011,19 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co } // ------------------------------------------------------------------------------------------------ -aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* /*camera*/, ConversionData& /*conv_data*/) +aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* cam, ConversionData& /*conv_data*/) { ScopeGuard out(new aiCamera()); out->mName = obj->id.name+2; out->mPosition = aiVector3D(0.f, 0.f, 0.f); out->mUp = aiVector3D(0.f, 1.f, 0.f); out->mLookAt = aiVector3D(0.f, 0.f, -1.f); + if (cam->sensor_x && cam->lens) { + out->mHorizontalFOV = atan2(cam->sensor_x, 2.f * cam->lens); + } + out->mClipPlaneNear = cam->clipsta; + out->mClipPlaneFar = cam->clipend; + return out.dismiss(); } diff --git a/code/BlenderLoader.h b/code/BlenderLoader.h index 9cf12656e..5933f89d6 100644 --- a/code/BlenderLoader.h +++ b/code/BlenderLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderModifier.cpp b/code/BlenderModifier.cpp index 13766c894..1e5d4e215 100644 --- a/code/BlenderModifier.cpp +++ b/code/BlenderModifier.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderModifier.h b/code/BlenderModifier.h index c5ea7f481..c9b62692b 100644 --- a/code/BlenderModifier.h +++ b/code/BlenderModifier.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderScene.cpp b/code/BlenderScene.cpp index 03831060b..1273de81e 100644 --- a/code/BlenderScene.cpp +++ b/code/BlenderScene.cpp @@ -620,7 +620,10 @@ template <> void Structure :: Convert ( ReadField(dest.id,"id",db); ReadField((int&)dest.type,"type",db); ReadField((int&)dest.flag,"flag",db); - ReadField(dest.angle,"angle",db); + ReadField(dest.lens,"lens",db); + ReadField(dest.sensor_x,"sensor_x",db); + ReadField(dest.clipsta,"clipsta",db); + ReadField(dest.clipend,"clipend",db); db.reader->IncPtr(size); } diff --git a/code/BlenderScene.h b/code/BlenderScene.h index 25c301891..0af1f3912 100644 --- a/code/BlenderScene.h +++ b/code/BlenderScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -312,18 +312,10 @@ struct Camera : ElemBase { ID id FAIL; - // struct AnimData *adt; - Type type,flag WARN; - float angle WARN; - //float passepartalpha, angle; - //float clipsta, clipend; - //float lens, ortho_scale, drawsize; - //float shiftx, shifty; - - //float YF_dofdist, YF_aperture; - //short YF_bkhtype, YF_bkhbias; - //float YF_bkhrot; + float lens WARN; + float sensor_x WARN; + float clipsta, clipend; }; diff --git a/code/BlobIOSystem.h b/code/BlobIOSystem.h index 7c43ae2b8..e157bb433 100644 --- a/code/BlobIOSystem.h +++ b/code/BlobIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/ByteSwapper.h b/code/ByteSwapper.h index b18595168..db499552b 100644 --- a/code/ByteSwapper.h +++ b/code/ByteSwapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CInterfaceIOWrapper.h b/code/CInterfaceIOWrapper.h index a9437b551..9032b8391 100644 --- a/code/CInterfaceIOWrapper.h +++ b/code/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -57,7 +57,7 @@ class CIOStreamWrapper : public IOStream friend class CIOSystemWrapper; public: - CIOStreamWrapper(aiFile* pFile) + explicit CIOStreamWrapper(aiFile* pFile) : mFile(pFile) {} @@ -110,7 +110,7 @@ private: class CIOSystemWrapper : public IOSystem { public: - CIOSystemWrapper(aiFileIO* pFile) + explicit CIOSystemWrapper(aiFileIO* pFile) : mFileSystem(pFile) {} diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index c3302ee98..5088d5433 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -113,6 +113,7 @@ SET( Common_SRCS StreamReader.h StreamWriter.h StringComparison.h + StringUtils.h SGSpatialSort.cpp SGSpatialSort.h VertexTriangleAdjacency.cpp @@ -530,6 +531,11 @@ ADD_ASSIMP_IMPORTER(RAW RawLoader.h ) +ADD_ASSIMP_IMPORTER(SIB + SIBImporter.cpp + SIBImporter.h +) + ADD_ASSIMP_IMPORTER(SMD SMDLoader.cpp SMDLoader.h @@ -562,6 +568,19 @@ ADD_ASSIMP_IMPORTER(X XFileExporter.cpp ) +ADD_ASSIMP_IMPORTER(GLTF + glTFAsset.h + glTFAsset.inl + glTFAssetWriter.h + glTFAssetWriter.inl + + glTFImporter.cpp + glTFImporter.h + + glTFExporter.h + glTFExporter.cpp +) + SET( Step_SRCS StepExporter.h StepExporter.cpp @@ -632,15 +651,20 @@ SOURCE_GROUP( unzip FILES ${unzip_SRCS}) SET ( openddl_parser_SRCS ../contrib/openddlparser/code/OpenDDLParser.cpp ../contrib/openddlparser/code/DDLNode.cpp + ../contrib/openddlparser/code/OpenDDLCommon.cpp + ../contrib/openddlparser/code/OpenDDLExport.cpp ../contrib/openddlparser/code/Value.cpp ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h + ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h ../contrib/openddlparser/include/openddlparser/DDLNode.h ../contrib/openddlparser/include/openddlparser/Value.h ) SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS}) +INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) + # VC2010 fixes if(MSVC10) option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) @@ -733,8 +757,10 @@ if( MSVC ) set(MSVC_PREFIX "vc110") elseif( MSVC12 ) set(MSVC_PREFIX "vc120") + elseif( MSVC14 ) + set(MSVC_PREFIX "vc140") else() - set(MSVC_PREFIX "vc130") + set(MSVC_PREFIX "vc150") endif() set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library") endif() @@ -766,13 +792,13 @@ INSTALL( TARGETS assimp INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) if (ASSIMP_ANDROID_JNIIOSYSTEM) - INSTALL(FILES ${HEADER_PATH}/../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h + INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} COMPONENT assimp-dev) endif(ASSIMP_ANDROID_JNIIOSYSTEM) if(MSVC AND ASSIMP_INSTALL_PDB) - install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${CMAKE_DEBUG_POSTFIX}.pdb + install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION ${ASSIMP_LIB_INSTALL_DIR} CONFIGURATIONS Debug ) diff --git a/code/COBLoader.cpp b/code/COBLoader.cpp index 88d5653f7..210913e19 100644 --- a/code/COBLoader.cpp +++ b/code/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/COBLoader.h b/code/COBLoader.h index aa6402227..efccc448d 100644 --- a/code/COBLoader.h +++ b/code/COBLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/COBScene.h b/code/COBScene.h index 7e7d3494d..d87ad3945 100644 --- a/code/COBScene.h +++ b/code/COBScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CSMLoader.cpp b/code/CSMLoader.cpp index 21ad41e94..064c82dd2 100644 --- a/code/CSMLoader.cpp +++ b/code/CSMLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/CSMLoader.h b/code/CSMLoader.h index 459b13711..71abb7e91 100644 --- a/code/CSMLoader.h +++ b/code/CSMLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index 71949feea..09302cc3e 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/CalcTangentsProcess.h b/code/CalcTangentsProcess.h index fbe71a1b5..4a6122668 100644 --- a/code/CalcTangentsProcess.h +++ b/code/CalcTangentsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 7f5333adc..dcf82a564 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -526,6 +526,13 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* } } +// ------------------------------------------------------------------------------------------------ +// Reimplementation of isalnum(,C locale), because AppVeyor does not see standard version. +static bool isalnum_C(char c) +{ + return strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",c); +} + // ------------------------------------------------------------------------------------------------ // Writes an image entry for the given surface void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) @@ -540,7 +547,7 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin std::stringstream imageUrlEncoded; for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) { - if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) + if( isalnum_C( (unsigned char) *it) || *it == ':' || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) imageUrlEncoded << *it; else imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; @@ -631,9 +638,7 @@ void ColladaExporter::WriteMaterials() name = "mat"; materials[a].name = std::string( "m") + boost::lexical_cast (a) + name.C_Str(); for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) { - // isalnum on MSVC asserts for code points outside [0,255]. Thus prevent unwanted promotion - // of char to signed int and take the unsigned char value. - if( !isalnum( static_cast(*it) ) ) { + if( !isalnum_C( *it ) ) { *it = '_'; } } @@ -875,6 +880,11 @@ void ColladaExporter::WriteGeometry( size_t pIndex) mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) + { + if( mesh->HasTextureCoords( a) ) + mOutput << startstr << "" << endstr; + } mOutput << startstr << ""; for( size_t a = 0; a < mesh->mNumFaces; ++a ) @@ -1070,8 +1080,19 @@ void ColladaExporter::WriteNode(aiNode* pNode) PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mMaterialIndex].name) << "\" />" << endstr; - PopTag(); + mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; + PushTag(); + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) + { + if( mesh->HasTextureCoords( a) ) + // semantic as in + // input_semantic as in + // input_set as in + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; diff --git a/code/ColladaExporter.h b/code/ColladaExporter.h index 858cef2b6..fcaf55ca6 100644 --- a/code/ColladaExporter.h +++ b/code/ColladaExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index 18ac09a85..0a635a559 100644 --- a/code/ColladaHelper.h +++ b/code/ColladaHelper.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -517,6 +517,7 @@ struct Effect float mTransparency; bool mHasTransparency; bool mRGBTransparency; + bool mInvertTransparency; // local params referring to each other by their SID typedef std::map ParamLibrary; @@ -536,10 +537,11 @@ struct Effect , mTransparent ( 0, 0, 0, 1) , mShininess (10.0f) , mRefractIndex (1.f) - , mReflectivity (1.f) + , mReflectivity (0.f) , mTransparency (1.f) , mHasTransparency (false) , mRGBTransparency(false) + , mInvertTransparency(false) , mDoubleSided (false) , mWireframe (false) , mFaceted (false) @@ -595,6 +597,48 @@ struct Animation for( std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) delete *it; } + + /** Collect all channels in the animation hierarchy into a single channel list. */ + void CollectChannelsRecursively(std::vector &channels) + { + channels.insert(channels.end(), mChannels.begin(), mChannels.end()); + + for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) + { + Animation *pAnim = (*it); + + pAnim->CollectChannelsRecursively(channels); + } + } + + /** Combine all single-channel animations' channel into the same (parent) animation channel list. */ + void CombineSingleChannelAnimations() + { + CombineSingleChannelAnimationsRecursively(this); + } + + void CombineSingleChannelAnimationsRecursively(Animation *pParent) + { + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) + { + Animation *anim = *it; + + CombineSingleChannelAnimationsRecursively(anim); + + if (anim->mChannels.size() == 1) + { + pParent->mChannels.push_back(anim->mChannels[0]); + + it = pParent->mSubAnims.erase(it); + + delete anim; + } + else + { + ++it; + } + } + } }; /** Description of a collada animation channel which has been determined to affect the current node */ diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index f11ce589a..e6dd3ecad 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Defines.h" #include "time.h" +#include "math.h" #include #include "../include/assimp/DefaultLogger.hpp" #include "../include/assimp/Importer.hpp" @@ -77,14 +78,21 @@ static const aiImporterDesc desc = { "dae" }; - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ColladaLoader::ColladaLoader() - : noSkeletonMesh() + : mFileName() + , mMeshIndexByID() + , mMaterialIndexByName() + , mMeshes() + , newMats() + , mCameras() + , mLights() + , mTextures() + , mAnims() + , noSkeletonMesh( false ) , ignoreUpDirection(false) - , invertTransparency(false) - , mNodeNameCounter() + , mNodeNameCounter( 0 ) {} // ------------------------------------------------------------------------------------------------ @@ -120,7 +128,6 @@ void ColladaLoader::SetupProperties(const Importer* pImp) { noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0; - invertTransparency = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_INVERT_TRANSPARENCY,0) != 0; } @@ -1163,6 +1170,25 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars } ++pos; } + + // https://github.com/assimp/assimp/issues/458 + // Sub-sample axis-angle channels if the delta between two consecutive + // key-frame angles is >= 180 degrees. + if (transforms[e.mTransformIndex].mType == Collada::TF_ROTATE && e.mSubElement == 3 && pos > 0 && pos < e.mTimeAccessor->mCount) { + float cur_key_angle = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, 0); + float last_key_angle = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, 0); + float cur_key_time = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0); + float last_key_time = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0); + float last_eval_angle = last_key_angle + (cur_key_angle - last_key_angle) * (time - last_key_time) / (cur_key_time - last_key_time); + float delta = std::fabs(cur_key_angle - last_eval_angle); + if (delta >= 180.0f) { + int subSampleCount = static_cast(floorf(delta / 90.0f)); + if (cur_key_time != time) { + float nextSampleTime = time + (cur_key_time - time) / subSampleCount; + nextTime = std::min(nextTime, nextSampleTime); + } + } + } } // no more keys on any channel after the current time -> we're done @@ -1341,7 +1367,6 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce mat.AddProperty( &effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); mat.AddProperty( &effect.mSpecular, 1,AI_MATKEY_COLOR_SPECULAR); mat.AddProperty( &effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - mat.AddProperty( &effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT); mat.AddProperty( &effect.mReflective, 1, AI_MATKEY_COLOR_REFLECTIVE); // scalar properties @@ -1354,20 +1379,29 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce // therefore, we let the opportunity for the user to manually invert // the transparency if necessary and we add preliminary support for RGB_ZERO mode if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) { - // Trying some support for RGB_ZERO mode + // handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304 if(effect.mRGBTransparency) { - effect.mTransparency = 1.f - effect.mTransparent.a; + // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4) + effect.mTransparency *= ( + 0.212671f * effect.mTransparent.r + + 0.715160f * effect.mTransparent.g + + 0.072169f * effect.mTransparent.b + ); + + effect.mTransparent.a = 1.f; + + mat.AddProperty( &effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT ); + } else { + effect.mTransparency *= effect.mTransparent.a; } - // Global option - if(invertTransparency) { + if(effect.mInvertTransparency) { effect.mTransparency = 1.f - effect.mTransparency; } // Is the material finally transparent ? if (effect.mHasTransparency || effect.mTransparency < 1.f) { mat.AddProperty( &effect.mTransparency, 1, AI_MATKEY_OPACITY ); - mat.AddProperty( &effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT ); } } diff --git a/code/ColladaLoader.h b/code/ColladaLoader.h index 5d3c830fe..313608cc2 100644 --- a/code/ColladaLoader.h +++ b/code/ColladaLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -241,7 +241,6 @@ protected: bool noSkeletonMesh; bool ignoreUpDirection; - bool invertTransparency; /** Used by FindNameForNode() to generate unique node names */ unsigned int mNodeNameCounter; diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index cdc3cedeb..f52ec677a 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -64,25 +64,41 @@ using namespace Assimp::Collada; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile) - : mFileName( pFile) + : mFileName( pFile ) + , mReader( NULL ) + , mDataLibrary() + , mAccessorLibrary() + , mMeshLibrary() + , mNodeLibrary() + , mImageLibrary() + , mEffectLibrary() + , mMaterialLibrary() + , mLightLibrary() + , mCameraLibrary() + , mControllerLibrary() + , mRootNode( NULL ) + , mAnims() + , mUnitSize( 1.0f ) + , mUpDirection( UP_Y ) + , mFormat(FV_1_5_n ) // We assume the newest file format by default { - mRootNode = NULL; - mUnitSize = 1.0f; - mUpDirection = UP_Y; + // validate io-handler instance + if ( NULL == pIOHandler ) { + throw DeadlyImportError("IOSystem is NULL." ); + } - // We assume the newest file format by default - mFormat = FV_1_5_n; - - // open the file - boost::scoped_ptr file( pIOHandler->Open( pFile)); - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open file " + pFile + "."); + // open the file + boost::scoped_ptr file( pIOHandler->Open(pFile ) ); + if (file.get() == NULL) { + throw DeadlyImportError( "Failed to open file " + pFile + "." ); + } // generate a XML reader for it - boost::scoped_ptr mIOWrapper( new CIrrXML_IOStreamReader( file.get())); + boost::scoped_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); mReader = irr::io::createIrrXMLReader( mIOWrapper.get()); - if( !mReader) - ThrowException( "Collada: Unable to open file."); + if (!mReader) { + ThrowException("Collada: Unable to open file."); + } // start reading ReadContents(); @@ -171,6 +187,8 @@ void ColladaParser::ReadStructure() ReadAssetInfo(); else if( IsElement( "library_animations")) ReadAnimationLibrary(); + else if (IsElement("library_animation_clips")) + ReadAnimationClipLibrary(); else if( IsElement( "library_controllers")) ReadControllerLibrary(); else if( IsElement( "library_images")) @@ -199,6 +217,8 @@ void ColladaParser::ReadStructure() break; } } + + PostProcessRootAnimations(); } // ------------------------------------------------------------------------------------------------ @@ -255,6 +275,131 @@ void ColladaParser::ReadAssetInfo() } } +// ------------------------------------------------------------------------------------------------ +// Reads the animation clips +void ColladaParser::ReadAnimationClipLibrary() +{ + if (mReader->isEmptyElement()) + return; + + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("animation_clip")) + { + // optional name given as an attribute + std::string animName; + int indexName = TestAttribute("name"); + int indexID = TestAttribute("id"); + if (indexName >= 0) + animName = mReader->getAttributeValue(indexName); + else if (indexID >= 0) + animName = mReader->getAttributeValue(indexID); + else + animName = "animation_" + mAnimationClipLibrary.size(); + + std::pair > clip; + + clip.first = animName; + + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("instance_animation")) + { + int indexUrl = TestAttribute("url"); + if (indexUrl >= 0) + { + const char* url = mReader->getAttributeValue(indexUrl); + if (url[0] != '#') + ThrowException("Unknown reference format"); + + url++; + + clip.second.push_back(url); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "animation_clip") != 0) + ThrowException("Expected end of element."); + + break; + } + } + + if (clip.second.size() > 0) + { + mAnimationClipLibrary.push_back(clip); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "library_animation_clips") != 0) + ThrowException("Expected end of element."); + + break; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Re-build animations from animation clip library, if present, otherwise combine single-channel animations +void ColladaParser::PostProcessRootAnimations() +{ + if (mAnimationClipLibrary.size() > 0) + { + Animation temp; + + for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) + { + std::string clipName = it->first; + + Animation *clip = new Animation(); + clip->mName = clipName; + + temp.mSubAnims.push_back(clip); + + for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) + { + std::string animationID = *a; + + AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); + + if (animation != mAnimationLibrary.end()) + { + Animation *pSourceAnimation = animation->second; + + pSourceAnimation->CollectChannelsRecursively(clip->mChannels); + } + } + } + + mAnims = temp; + + // Ensure no double deletes. + temp.mSubAnims.clear(); + } + else + { + mAnims.CombineSingleChannelAnimations(); + } +} + // ------------------------------------------------------------------------------------------------ // Reads the animation library void ColladaParser::ReadAnimationLibrary() @@ -302,12 +447,17 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // optional name given as an attribute std::string animName; + std::string animID; int indexName = TestAttribute( "name"); int indexID = TestAttribute( "id"); + + if (indexID >= 0) + animID = mReader->getAttributeValue(indexID); + if( indexName >= 0) animName = mReader->getAttributeValue( indexName); else if( indexID >= 0) - animName = mReader->getAttributeValue( indexID); + animName = animID; else animName = "animation"; @@ -379,11 +529,19 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // it turned out to have channels - add them if( !channels.empty()) { + // FIXME: Is this essentially doing the same as "single-anim-node" codepath in + // ColladaLoader::StoreAnimations? For now, this has been deferred to after + // all animations and all clips have been read. Due to handling of + // this cannot be done here, as the channel owner + // is lost, and some exporters make up animations by referring to multiple + // single-channel animations from an . +/* // special filtering for stupid exporters packing each channel into a separate animation if( channels.size() == 1) { pParent->mChannels.push_back( channels.begin()->second); } else +*/ { // else create the animation, if not done yet, and store the channels if( !anim) @@ -394,6 +552,11 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) } for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) anim->mChannels.push_back( it->second); + + if (indexID >= 0) + { + mAnimationLibrary[animID] = anim; + } } } } @@ -832,7 +995,7 @@ void ColladaParser::ReadMaterialLibrary() { if( IsElement( "material")) { - // read ID. By now you propably know my opinion about this "specification" + // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute( "id"); std::string id = mReader->getAttributeValue( attrID); @@ -890,7 +1053,7 @@ void ColladaParser::ReadLightLibrary() if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { if( IsElement( "light")) { - // read ID. By now you propably know my opinion about this "specification" + // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute( "id"); std::string id = mReader->getAttributeValue( attrID); @@ -924,7 +1087,7 @@ void ColladaParser::ReadCameraLibrary() if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { if( IsElement( "camera")) { - // read ID. By now you propably know my opinion about this "specification" + // read ID. By now you probably know my opinion about this "specification" int attrID = GetAttribute( "id"); std::string id = mReader->getAttributeValue( attrID); @@ -1240,12 +1403,17 @@ void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect) else if( IsElement( "transparent")) { pEffect.mHasTransparency = true; - // In RGB_ZERO mode, the transparency is interpreted in reverse, go figure... - if(::strcmp(mReader->getAttributeValueSafe("opaque"), "RGB_ZERO") == 0) { - // TODO: handle RGB_ZERO mode completely + const char* opaque = mReader->getAttributeValueSafe("opaque"); + + if(::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "RGB_ONE") == 0) { pEffect.mRGBTransparency = true; } + // In RGB_ZERO mode, the transparency is interpreted in reverse, go figure... + if(::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "A_ZERO") == 0) { + pEffect.mInvertTransparency = true; + } + ReadEffectColor( pEffect.mTransparent,pEffect.mTexTransparent); } else if( IsElement( "shininess")) @@ -1509,7 +1677,7 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam) // don't care for remaining stuff SkipElement( "surface"); } - else if( IsElement( "sampler2D")) + else if( IsElement( "sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) { // surface ID is given inside tags TestOpening( "source"); @@ -1520,6 +1688,19 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam) // don't care for remaining stuff SkipElement( "sampler2D"); + } + else if( IsElement( "sampler2D")) + { + // surface ID is given inside tags + TestOpening( "instance_image"); + int attrURL = GetAttribute("url"); + const char* url = mReader->getAttributeValue( attrURL); + if( url[0] != '#') + ThrowException( "Unsupported URL format in instance_image"); + url++; + pParam.mType = Param_Sampler; + pParam.mReference = url; + SkipElement( "sampler2D"); } else { // ignore unknown element @@ -1947,7 +2128,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) ai_assert( primType != Prim_Invalid); - // also a number of elements, but in addition a

primitive collection and propably index counts for all primitives + // also a number of elements, but in addition a

primitive collection and probably index counts for all primitives while( mReader->read()) { if( mReader->getNodeType() == irr::io::EXN_ELEMENT) diff --git a/code/ColladaParser.h b/code/ColladaParser.h index a945b70a7..14d2f8d4b 100644 --- a/code/ColladaParser.h +++ b/code/ColladaParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- - Copyright (c) 2006-2015, assimp team + Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -49,6 +49,7 @@ #include "ColladaHelper.h" #include "../include/assimp/ai_assert.h" #include +#include namespace Assimp { @@ -81,6 +82,12 @@ namespace Assimp /** Reads the animation library */ void ReadAnimationLibrary(); + + /** Reads the animation clip library */ + void ReadAnimationClipLibrary(); + + /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */ + void PostProcessRootAnimations(); /** Reads an animation into the given parent structure */ void ReadAnimation( Collada::Animation* pParent); @@ -311,6 +318,14 @@ namespace Assimp /** Controller library: joint controllers by ID */ typedef std::map ControllerLibrary; ControllerLibrary mControllerLibrary; + + /** Animation library: animation references by ID */ + typedef std::map AnimationLibrary; + AnimationLibrary mAnimationLibrary; + + /** Animation clip library: clip animation references by ID */ + typedef std::vector > > AnimationClipLibrary; + AnimationClipLibrary mAnimationClipLibrary; /** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */ diff --git a/code/ComputeUVMappingProcess.cpp b/code/ComputeUVMappingProcess.cpp index 00357a173..2bbb30be8 100644 --- a/code/ComputeUVMappingProcess.cpp +++ b/code/ComputeUVMappingProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -412,7 +412,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene) { if (!DefaultLogger::isNullLogger()) { - sprintf(buffer, "Found non-UV mapped texture (%s,%u). Mapping type: %s", + ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, MappingTypeToString(mapping)); diff --git a/code/ComputeUVMappingProcess.h b/code/ComputeUVMappingProcess.h index 4b829eda5..fd138ef86 100644 --- a/code/ComputeUVMappingProcess.h +++ b/code/ComputeUVMappingProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -125,7 +125,7 @@ private: // temporary structure to describe a mapping struct MappingInfo { - MappingInfo(aiTextureMapping _type) + explicit MappingInfo(aiTextureMapping _type) : type (_type) , axis (0.f,1.f,0.f) , uv (0u) diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index a7f0b2218..05f8acd14 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/ConvertToLHProcess.h b/code/ConvertToLHProcess.h index d4a8e360a..8c34056f7 100644 --- a/code/ConvertToLHProcess.h +++ b/code/ConvertToLHProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DXFHelper.h b/code/DXFHelper.h index a438c6de8..f18543509 100644 --- a/code/DXFHelper.h +++ b/code/DXFHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -66,6 +66,8 @@ public: LineReader(StreamReaderLE& reader) // do NOT skip empty lines. In DXF files, they count as valid data. : splitter(reader,false,true) + , groupcode( 0 ) + , value() , end() { } diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index 9a68099ec..2f0f944e8 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/DXFLoader.h b/code/DXFLoader.h index 375a82ce1..13af4cdec 100644 --- a/code/DXFLoader.h +++ b/code/DXFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DeboneProcess.cpp b/code/DeboneProcess.cpp index f6780b97d..5d688f813 100644 --- a/code/DeboneProcess.cpp +++ b/code/DeboneProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -147,7 +147,7 @@ void DeboneProcess::Execute( aiScene* pScene) if(!DefaultLogger::isNullLogger()) { char buffer[1024]; - ::sprintf(buffer,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out); + ::ai_snprintf(buffer,1024,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out); DefaultLogger::get()->info(buffer); } diff --git a/code/DeboneProcess.h b/code/DeboneProcess.h index c83a89b75..82f533841 100644 --- a/code/DeboneProcess.h +++ b/code/DeboneProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DefaultIOStream.cpp b/code/DefaultIOStream.cpp index f61f74955..a6ca86484 100644 --- a/code/DefaultIOStream.cpp +++ b/code/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/DefaultIOStream.h b/code/DefaultIOStream.h index ae938b24d..c83f958d4 100644 --- a/code/DefaultIOStream.h +++ b/code/DefaultIOStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DefaultIOSystem.cpp b/code/DefaultIOSystem.cpp index 89d40e2a5..ef142b178 100644 --- a/code/DefaultIOSystem.cpp +++ b/code/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -176,7 +176,6 @@ std::string DefaultIOSystem::fileName( const std::string &path ) return ret; } - // ------------------------------------------------------------------------------------------------ std::string DefaultIOSystem::completeBaseName( const std::string &path ) { diff --git a/code/DefaultIOSystem.h b/code/DefaultIOSystem.h index cc2118fb9..32d191c2d 100644 --- a/code/DefaultIOSystem.h +++ b/code/DefaultIOSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DefaultLogger.cpp b/code/DefaultLogger.cpp index 22363551c..ed6ef4d8c 100644 --- a/code/DefaultLogger.cpp +++ b/code/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Win32DebugLogStream.h" #include "StdOStreamLogStream.h" #include "FileLogStream.h" +#include "StringUtils.h" #include "../include/assimp/NullLogger.hpp" #include "../include/assimp/DefaultLogger.hpp" #include "../include/assimp/ai_assert.h" @@ -226,9 +227,7 @@ bool DefaultLogger::isNullLogger() } // ---------------------------------------------------------------------------------- -// Singleton getter -Logger *DefaultLogger::get() -{ +Logger *DefaultLogger::get() { return m_pLogger; } @@ -241,7 +240,9 @@ void DefaultLogger::kill() boost::mutex::scoped_lock lock(loggerMutex); #endif - if (m_pLogger == &s_pNullLogger)return; + if ( m_pLogger == &s_pNullLogger ) { + return; + } delete m_pLogger; m_pLogger = &s_pNullLogger; } @@ -253,8 +254,9 @@ void DefaultLogger::OnDebug( const char* message ) if ( m_Severity == Logger::NORMAL ) return; - char msg[MAX_LOG_MESSAGE_LENGTH + 16]; - ::sprintf(msg,"Debug, T%u: %s", GetThreadID(), message ); + static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; + char msg[Size]; + ai_snprintf(msg, Size, "Debug, T%u: %s", GetThreadID(), message); WriteToStreams( msg, Logger::Debugging ); } @@ -263,8 +265,9 @@ void DefaultLogger::OnDebug( const char* message ) // Logs an info void DefaultLogger::OnInfo( const char* message ) { - char msg[MAX_LOG_MESSAGE_LENGTH + 16]; - ::sprintf(msg,"Info, T%u: %s", GetThreadID(), message ); + static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; + char msg[Size]; + ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message ); WriteToStreams( msg , Logger::Info ); } @@ -273,8 +276,9 @@ void DefaultLogger::OnInfo( const char* message ) // Logs a warning void DefaultLogger::OnWarn( const char* message ) { - char msg[MAX_LOG_MESSAGE_LENGTH + 16]; - ::sprintf(msg,"Warn, T%u: %s", GetThreadID(), message ); + static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; + char msg[Size]; + ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message ); WriteToStreams( msg, Logger::Warn ); } @@ -283,8 +287,9 @@ void DefaultLogger::OnWarn( const char* message ) // Logs an error void DefaultLogger::OnError( const char* message ) { - char msg[MAX_LOG_MESSAGE_LENGTH + 16]; - ::sprintf(msg,"Error, T%u: %s", GetThreadID(), message ); + static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; + char msg[ Size ]; + ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message ); WriteToStreams( msg, Logger::Err ); } @@ -317,7 +322,7 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) } // ---------------------------------------------------------------------------------- -// Detatch a stream +// Detach a stream bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) { if (!pStream) @@ -351,7 +356,6 @@ bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) // ---------------------------------------------------------------------------------- // Constructor DefaultLogger::DefaultLogger(LogSeverity severity) - : Logger ( severity ) , noRepeatMsg (false) , lastLen( 0 ) @@ -371,8 +375,7 @@ DefaultLogger::~DefaultLogger() // ---------------------------------------------------------------------------------- // Writes message to stream -void DefaultLogger::WriteToStreams(const char *message, - ErrorSeverity ErrorSev ) +void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) { ai_assert(NULL != message); diff --git a/code/DefaultProgressHandler.h b/code/DefaultProgressHandler.h index 3918c5714..8c0abfbfc 100644 --- a/code/DefaultProgressHandler.h +++ b/code/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 42044b111..888a65bd0 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -87,6 +87,8 @@ void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportPro void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*); void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); @@ -135,6 +137,13 @@ Exporter::ExportFormatEntry gExporters[] = aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices), #endif +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER + Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, + aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), + Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, + aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), +#endif + #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0), #endif diff --git a/code/FBXAnimation.cpp b/code/FBXAnimation.cpp index ab01c5581..dc5550ec9 100644 --- a/code/FBXAnimation.cpp +++ b/code/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index 68b2a2df3..fdb5c28df 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXCompileConfig.h b/code/FBXCompileConfig.h index 17f3f9ade..901f5b330 100644 --- a/code/FBXCompileConfig.h +++ b/code/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index e0c6b9ca2..c1a816dd8 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXUtil.h" #include "FBXProperties.h" #include "FBXImporter.h" +#include "StringComparison.h" #include "../include/assimp/scene.h" #include #include @@ -148,6 +149,7 @@ public: std::for_each(animations.begin(),animations.end(),Util::delete_fun()); std::for_each(lights.begin(),lights.end(),Util::delete_fun()); std::for_each(cameras.begin(),cameras.end(),Util::delete_fun()); + std::for_each(textures.begin(),textures.end(),Util::delete_fun()); } @@ -1449,6 +1451,36 @@ private: return static_cast(materials.size() - 1); } + // ------------------------------------------------------------------------------------------------ + // Video -> aiTexture + unsigned int ConvertVideo(const Video& video) + { + // generate empty output texture + aiTexture* out_tex = new aiTexture(); + textures.push_back(out_tex); + + // assuming the texture is compressed + out_tex->mWidth = static_cast(video.ContentLength()); // total data size + out_tex->mHeight = 0; // fixed to 0 + + // steal the data from the Video to avoid an additional copy + out_tex->pcData = reinterpret_cast( const_cast(video).RelinquishContent() ); + + // try to extract a hint from the file extension + const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName(); + std::string ext = BaseImporter::GetExtension(filename); + + if(ext == "jpeg") { + ext = "jpg"; + } + + if(ext.size() <= 3) { + memcpy(out_tex->achFormatHint, ext.c_str(), ext.size()); + } + + return static_cast(textures.size() - 1); + } + // ------------------------------------------------------------------------------------------------ void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, @@ -1466,6 +1498,24 @@ private: aiString path; path.Set(tex->RelativeFilename()); + const Video* media = tex->Media(); + if(media != 0 && media->ContentLength() > 0) { + unsigned int index; + + VideoMap::const_iterator it = textures_converted.find(media); + if(it != textures_converted.end()) { + index = (*it).second; + } + else { + index = ConvertVideo(*media); + textures_converted[media] = index; + } + + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + path.data[0] = '*'; + path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); + } + out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0); aiUVTransform uvTrafo; @@ -2496,8 +2546,9 @@ private: // need to convert from TRS order to SRT? if(reverse_order) { - aiVector3D def_scale, def_translate; - aiQuaternion def_rot; + aiVector3D def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f)); + aiVector3D def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f)); + aiVector3D def_rot = PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)); KeyFrameListList scaling; KeyFrameListList translation; @@ -2506,24 +2557,14 @@ private: if(chain[TransformationComp_Scaling] != iter_end) { scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop); } - else { - def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f)); - } if(chain[TransformationComp_Translation] != iter_end) { translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop); } - else { - def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f)); - } if(chain[TransformationComp_Rotation] != iter_end) { rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop); } - else { - def_rot = EulerToQuaternion(PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)), - target.RotationOrder()); - } KeyFrameListList joined; joined.insert(joined.end(), scaling.begin(), scaling.end()); @@ -2740,7 +2781,7 @@ private: // ------------------------------------------------------------------------------------------------ void InterpolateKeys(aiVectorKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs, - const bool geom, + const aiVector3D& def_value, double& max_time, double& min_time) @@ -2754,10 +2795,7 @@ private: next_pos.resize(inputs.size(),0); BOOST_FOREACH(KeyTimeList::value_type time, keys) { - float result[3] = {0.0f, 0.0f, 0.0f}; - if(geom) { - result[0] = result[1] = result[2] = 1.0f; - } + float result[3] = {def_value.x, def_value.y, def_value.z}; for (size_t i = 0; i < count; ++i) { const KeyFrameList& kfl = inputs[i]; @@ -2782,12 +2820,7 @@ private: const double factor = timeB == timeA ? 0. : static_cast((time - timeA) / (timeB - timeA)); const float interpValue = static_cast(valueA + (valueB - valueA) * factor); - if(geom) { - result[kfl.get<2>()] *= interpValue; - } - else { - result[kfl.get<2>()] += interpValue; - } + result[kfl.get<2>()] = interpValue; } // magic value to convert fbx times to seconds @@ -2807,7 +2840,7 @@ private: // ------------------------------------------------------------------------------------------------ void InterpolateKeys(aiQuatKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs, - const bool geom, + const aiVector3D& def_value, double& maxTime, double& minTime, Model::RotOrder order) @@ -2816,7 +2849,7 @@ private: ai_assert(valOut); boost::scoped_array temp(new aiVectorKey[keys.size()]); - InterpolateKeys(temp.get(),keys,inputs,geom,maxTime, minTime); + InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime); aiMatrix4x4 m; @@ -2858,20 +2891,20 @@ private: Model::RotOrder order, const aiVector3D& def_scale, const aiVector3D& def_translate, - const aiQuaternion& def_rotation) + const aiVector3D& def_rotation) { if (rotation.size()) { - InterpolateKeys(out_quat, times, rotation, false, maxTime, minTime, order); + InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order); } else { for (size_t i = 0; i < times.size(); ++i) { out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_quat[i].mValue = def_rotation; + out_quat[i].mValue = EulerToQuaternion(def_rotation, order); } } if (scaling.size()) { - InterpolateKeys(out_scale, times, scaling, true, maxTime, minTime); + InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime); } else { for (size_t i = 0; i < times.size(); ++i) { @@ -2881,7 +2914,7 @@ private: } if (translation.size()) { - InterpolateKeys(out_translation, times, translation, false, maxTime, minTime); + InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime); } else { for (size_t i = 0; i < times.size(); ++i) { @@ -2935,7 +2968,7 @@ private: na->mNumScalingKeys = static_cast(keys.size()); na->mScalingKeys = new aiVectorKey[keys.size()]; if (keys.size() > 0) - InterpolateKeys(na->mScalingKeys, keys, inputs, true, maxTime, minTime); + InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime); } @@ -2955,7 +2988,7 @@ private: na->mNumPositionKeys = static_cast(keys.size()); na->mPositionKeys = new aiVectorKey[keys.size()]; if (keys.size() > 0) - InterpolateKeys(na->mPositionKeys, keys, inputs, false, maxTime, minTime); + InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime); } @@ -2976,7 +3009,7 @@ private: na->mNumRotationKeys = static_cast(keys.size()); na->mRotationKeys = new aiQuatKey[keys.size()]; if (keys.size() > 0) - InterpolateKeys(na->mRotationKeys, keys, inputs, false, maxTime, minTime, order); + InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order); } @@ -3024,6 +3057,13 @@ private: std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras); } + + if(textures.size()) { + out->mTextures = new aiTexture*[textures.size()](); + out->mNumTextures = static_cast(textures.size()); + + std::swap_ranges(textures.begin(),textures.end(),out->mTextures); + } } @@ -3037,10 +3077,14 @@ private: std::vector animations; std::vector lights; std::vector cameras; + std::vector textures; typedef std::map MaterialMap; MaterialMap materials_converted; + typedef std::map VideoMap; + VideoMap textures_converted; + typedef std::map > MeshMap; MeshMap meshes_converted; diff --git a/code/FBXConverter.h b/code/FBXConverter.h index 2fcd3e76b..2e38c3a8a 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXDeformer.cpp b/code/FBXDeformer.cpp index b7128491a..4df8d97b1 100644 --- a/code/FBXDeformer.cpp +++ b/code/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -131,7 +131,7 @@ Cluster::~Cluster() // ------------------------------------------------------------------------------------------------ Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Deformer(id,element,doc,name) -{ +, accuracy( 0.0f ) { const Scope& sc = GetRequiredScope(element); const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"]; diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index 67ca99466..b59527611 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -180,6 +180,9 @@ const Object* LazyObject::Get(bool dieOnError) else if (!strncmp(obtype,"LayeredTexture",length)) { object.reset(new LayeredTexture(id,element,doc,name)); } + else if (!strncmp(obtype,"Video",length)) { + object.reset(new Video(id,element,doc,name)); + } else if (!strncmp(obtype,"AnimationStack",length)) { object.reset(new AnimationStack(id,element,name,doc)); } @@ -483,6 +486,11 @@ void Document::ReadConnections() for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { const Element& el = *(*it).second; const std::string& type = ParseTokenAsString(GetRequiredToken(el,0)); + + // PP = property-property connection, ignored for now + // (tokens: "PP", ID1, "Property1", ID2, "Property2") + if(type == "PP") continue; + const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1)); const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2)); diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 6a0c71c8a..994797d74 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -73,6 +73,8 @@ namespace FBX { class Material; class Geometry; + class Video; + class AnimationCurve; class AnimationCurveNode; class AnimationLayer; @@ -571,6 +573,10 @@ public: return crop; } + const Video* Media() const { + return media; + } + private: aiVector2D uvTrans; @@ -583,6 +589,8 @@ private: boost::shared_ptr props; unsigned int crop[4]; + + const Video* media; }; /** DOM class for layered FBX textures */ @@ -654,6 +662,59 @@ typedef std::fbx_unordered_map TextureMap; typedef std::fbx_unordered_map LayeredTextureMap; +/** DOM class for generic FBX videos */ +class Video : public Object +{ +public: + + Video(uint64_t id, const Element& element, const Document& doc, const std::string& name); + ~Video(); + +public: + + const std::string& Type() const { + return type; + } + + const std::string& FileName() const { + return fileName; + } + + const std::string& RelativeFilename() const { + return relativeFileName; + } + + const PropertyTable& Props() const { + ai_assert(props.get()); + return *props.get(); + } + + const uint8_t* Content() const { + ai_assert(content); + return content; + } + + const uint32_t ContentLength() const { + return contentLength; + } + + uint8_t* RelinquishContent() { + uint8_t* ptr = content; + content = 0; + return ptr; + } + +private: + + std::string type; + std::string relativeFileName; + std::string fileName; + boost::shared_ptr props; + + uint32_t contentLength; + uint8_t* content; +}; + /** DOM class for generic FBX materials */ class Material : public Object { diff --git a/code/FBXDocumentUtil.cpp b/code/FBXDocumentUtil.cpp index 6fa3042e7..a95788e78 100644 --- a/code/FBXDocumentUtil.cpp +++ b/code/FBXDocumentUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXImportSettings.h b/code/FBXImportSettings.h index 13c266ada..df7cdbd37 100644 --- a/code/FBXImportSettings.h +++ b/code/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -55,6 +55,7 @@ struct ImportSettings , readAllLayers(true) , readAllMaterials(false) , readMaterials(true) + , readTextures(true) , readCameras(true) , readLights(true) , readAnimations(true) @@ -92,6 +93,9 @@ struct ImportSettings * material. The default value is true.*/ bool readMaterials; + /** import embedded textures? Default value is true.*/ + bool readTextures; + /** import cameras? Default value is true.*/ bool readCameras; diff --git a/code/FBXImporter.cpp b/code/FBXImporter.cpp index d7e4926aa..a8ebc3e61 100644 --- a/code/FBXImporter.cpp +++ b/code/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -126,6 +126,7 @@ void FBXImporter::SetupProperties(const Importer* pImp) settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); + settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); diff --git a/code/FBXImporter.h b/code/FBXImporter.h index 455dc3aed..0c50709fc 100644 --- a/code/FBXImporter.h +++ b/code/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index 03f292168..c14140319 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXImportSettings.h" #include "FBXDocumentUtil.h" #include "FBXProperties.h" +#include "ByteSwapper.h" #include namespace Assimp { @@ -147,6 +148,7 @@ Material::~Material() Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Object(id,element,name) , uvScaling(1.0f,1.0f) +, media(0) { const Scope& sc = GetRequiredScope(element); @@ -199,6 +201,23 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const } props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc); + + // resolve video links + if(doc.Settings().readTextures) { + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + BOOST_FOREACH(const Connection* con, conns) { + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for texture link, ignoring",&element); + continue; + } + + const Video* const video = dynamic_cast(ob); + if(video) { + media = video; + } + } + } } @@ -253,6 +272,68 @@ void LayeredTexture::fillTexture(const Document& doc) } } + +// ------------------------------------------------------------------------------------------------ +Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name) +: Object(id,element,name) +, contentLength(0) +, content(0) +{ + const Scope& sc = GetRequiredScope(element); + + const Element* const Type = sc["Type"]; + const Element* const FileName = sc["FileName"]; + const Element* const RelativeFilename = sc["RelativeFilename"]; + const Element* const Content = sc["Content"]; + + if(Type) { + type = ParseTokenAsString(GetRequiredToken(*Type,0)); + } + + if(FileName) { + fileName = ParseTokenAsString(GetRequiredToken(*FileName,0)); + } + + if(RelativeFilename) { + relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); + } + + if(Content) { + const Token& token = GetRequiredToken(*Content, 0); + const char* data = token.begin(); + if(!token.IsBinary()) { + DOMWarning("video content is not binary data, ignoring", &element); + } + else if(static_cast(token.end() - data) < 5) { + DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element); + } + else if(*data != 'R') { + DOMWarning("video content is not raw binary data, ignoring", &element); + } + else { + // read number of elements + uint32_t len = 0; + ::memcpy(&len, data + 1, sizeof(len)); + AI_SWAP4(len); + + contentLength = len; + + content = new uint8_t[len]; + ::memcpy(content, data + 5, len); + } + } + + props = GetPropertyTable(doc,"Video.FbxVideo",element,sc); +} + + +Video::~Video() +{ + if(content) { + delete[] content; + } +} + } //!FBX } //!Assimp diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index 45476d8c1..28ce924cb 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -347,23 +347,28 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, const std::vector& mapping_offsets, const std::vector& mappings) { - std::vector tempUV; - ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName)); + // handle permutations of Mapping and Reference type - it would be nice to // deal with this more elegantly and with less redundancy, but right // now it seems unavoidable. if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") { + std::vector tempData; + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + data_out.resize(vertex_count); - for (size_t i = 0, e = tempUV.size(); i < e; ++i) { + for (size_t i = 0, e = tempData.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; for (unsigned int j = istart; j < iend; ++j) { - data_out[mappings[j]] = tempUV[i]; + data_out[mappings[j]] = tempData[i]; } } } else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") { + std::vector tempData; + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + data_out.resize(vertex_count); std::vector uvIndices; @@ -373,24 +378,30 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; for (unsigned int j = istart; j < iend; ++j) { - if(static_cast(uvIndices[i]) >= tempUV.size()) { + if (static_cast(uvIndices[i]) >= tempData.size()) { DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); } - data_out[mappings[j]] = tempUV[uvIndices[i]]; + data_out[mappings[j]] = tempData[uvIndices[i]]; } } } else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") { - if (tempUV.size() != vertex_count) { + std::vector tempData; + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + + if (tempData.size() != vertex_count) { FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << tempUV.size() << ", expected " << vertex_count + << tempData.size() << ", expected " << vertex_count ); return; } - data_out.swap(tempUV); + data_out.swap(tempData); } else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") { + std::vector tempData; + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + data_out.resize(vertex_count); std::vector uvIndices; @@ -403,11 +414,11 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, unsigned int next = 0; BOOST_FOREACH(int i, uvIndices) { - if(static_cast(i) >= tempUV.size()) { + if (static_cast(i) >= tempData.size()) { DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); } - data_out[next++] = tempUV[i]; + data_out[next++] = tempData[i]; } } else { @@ -460,32 +471,38 @@ void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, cons mappings); } - // ------------------------------------------------------------------------------------------------ +static const std::string TangentIndexToken = "TangentIndex"; +static const std::string TangentsIndexToken = "TangentsIndex"; + void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType) { const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; + const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken.c_str() : TangentIndexToken.c_str(); ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, str, - "TangentIndex", + strIdx, vertices.size(), mapping_counts, mapping_offsets, mappings); } - // ------------------------------------------------------------------------------------------------ +static const std::string BinormalIndexToken = "BinormalIndex"; +static const std::string BinormalsIndexToken = "BinormalsIndex"; + void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType) { const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal"; + const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str(); ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, str, - "BinormalIndex", + strIdx, vertices.size(), mapping_counts, mapping_offsets, diff --git a/code/FBXModel.cpp b/code/FBXModel.cpp index 38e0c62de..c16439724 100644 --- a/code/FBXModel.cpp +++ b/code/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXNodeAttribute.cpp b/code/FBXNodeAttribute.cpp index e33205496..2bb00248b 100644 --- a/code/FBXNodeAttribute.cpp +++ b/code/FBXNodeAttribute.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXParser.cpp b/code/FBXParser.cpp index 0368d52e9..09a18b6e0 100644 --- a/code/FBXParser.cpp +++ b/code/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -125,13 +125,20 @@ Element::Element(const Token& key_token, Parser& parser) if (n->Type() == TokenType_DATA) { tokens.push_back(n); - + TokenPtr prev = n; n = parser.AdvanceToNextToken(); if(!n) { ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken()); } - const TokenType ty = n->Type(); + const TokenType ty = n->Type(); + + // some exporters are missing a comma on the next line + if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) { + tokens.push_back(n); + continue; + } + if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { ParseError("unexpected token; expected bracket, comma or key",n); } diff --git a/code/FBXParser.h b/code/FBXParser.h index 17bd740c2..e72a92611 100644 --- a/code/FBXParser.h +++ b/code/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXProperties.cpp b/code/FBXProperties.cpp index 0cf575b31..053cd530f 100644 --- a/code/FBXProperties.cpp +++ b/code/FBXProperties.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXProperties.h b/code/FBXProperties.h index 455a2aedb..0346e9b31 100644 --- a/code/FBXProperties.h +++ b/code/FBXProperties.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -87,7 +87,7 @@ class TypedProperty : public Property { public: - TypedProperty(const T& value) + explicit TypedProperty(const T& value) : value(value) { } diff --git a/code/FBXTokenizer.cpp b/code/FBXTokenizer.cpp index b465c7863..7ede49f39 100644 --- a/code/FBXTokenizer.cpp +++ b/code/FBXTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXTokenizer.h b/code/FBXTokenizer.h index 0e3b839d8..5098a97e8 100644 --- a/code/FBXTokenizer.h +++ b/code/FBXTokenizer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXUtil.cpp b/code/FBXUtil.cpp index 7a7e6b993..601d5e214 100644 --- a/code/FBXUtil.cpp +++ b/code/FBXUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXUtil.h b/code/FBXUtil.h index 7e398053d..331a769ff 100644 --- a/code/FBXUtil.h +++ b/code/FBXUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FindDegenerates.cpp b/code/FindDegenerates.cpp index a6df5ed84..62750bfad 100644 --- a/code/FindDegenerates.cpp +++ b/code/FindDegenerates.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/FindDegenerates.h b/code/FindDegenerates.h index c164c66de..5dffd8a5e 100644 --- a/code/FindDegenerates.h +++ b/code/FindDegenerates.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FindInstancesProcess.cpp b/code/FindInstancesProcess.cpp index b5d67144b..10bcc4765 100644 --- a/code/FindInstancesProcess.cpp +++ b/code/FindInstancesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -267,7 +267,7 @@ void FindInstancesProcess::Execute( aiScene* pScene) if (!DefaultLogger::isNullLogger()) { char buffer[512]; - ::sprintf(buffer,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut); + ::ai_snprintf(buffer,512,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut); DefaultLogger::get()->info(buffer); } pScene->mNumMeshes = numMeshesOut; diff --git a/code/FindInstancesProcess.h b/code/FindInstancesProcess.h index e2c9a1315..14876045c 100644 --- a/code/FindInstancesProcess.h +++ b/code/FindInstancesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FindInvalidDataProcess.cpp b/code/FindInvalidDataProcess.cpp index 210a255a2..bb87f8dd8 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/FindInvalidDataProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/FindInvalidDataProcess.h b/code/FindInvalidDataProcess.h index bdaa767ce..6fdd000ed 100644 --- a/code/FindInvalidDataProcess.h +++ b/code/FindInvalidDataProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FixNormalsStep.cpp b/code/FixNormalsStep.cpp index 5fe139e4b..5360e5b83 100644 --- a/code/FixNormalsStep.cpp +++ b/code/FixNormalsStep.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "FixNormalsStep.h" +#include "StringUtils.h" #include "../include/assimp/DefaultLogger.hpp" #include "../include/assimp/postprocess.h" #include "../include/assimp/scene.h" @@ -158,7 +159,7 @@ bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index) if (!DefaultLogger::isNullLogger()) { char buffer[128]; // should be sufficiently large - ::sprintf(buffer,"Mesh %u: Normals are facing inwards (or the mesh is planar)",index); + ai_snprintf(buffer,128,"Mesh %u: Normals are facing inwards (or the mesh is planar)",index); DefaultLogger::get()->info(buffer); } diff --git a/code/FixNormalsStep.h b/code/FixNormalsStep.h index ee08b62a6..5dea5d868 100644 --- a/code/FixNormalsStep.h +++ b/code/FixNormalsStep.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenFaceNormalsProcess.cpp b/code/GenFaceNormalsProcess.cpp index f4a568122..d0155e0e2 100644 --- a/code/GenFaceNormalsProcess.cpp +++ b/code/GenFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/GenFaceNormalsProcess.h b/code/GenFaceNormalsProcess.h index 89b719963..d1c367e1e 100644 --- a/code/GenFaceNormalsProcess.h +++ b/code/GenFaceNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenVertexNormalsProcess.cpp b/code/GenVertexNormalsProcess.cpp index 1d50e2a1f..165c3f8fb 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/GenVertexNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -56,14 +56,13 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer GenVertexNormalsProcess::GenVertexNormalsProcess() -{ - this->configMaxAngle = AI_DEG_TO_RAD(175.f); +: configMaxAngle( AI_DEG_TO_RAD( 175.f ) ) { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -GenVertexNormalsProcess::~GenVertexNormalsProcess() -{ +GenVertexNormalsProcess::~GenVertexNormalsProcess() { // nothing to do here } @@ -192,7 +191,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int const aiVector3D& v = pMesh->mNormals[verticesFound[a]]; if (is_not_qnan(v.x))pcNor += v; } - pcNor.Normalize(); + pcNor.NormalizeSafe(); // Write the smoothed normal back to all affected normals for (unsigned int a = 0; a < verticesFound.size(); ++a) @@ -225,7 +224,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int if (v * vr >= fLimit * vrlen * v.Length()) pcNor += v; } - pcNew[i] = pcNor.Normalize(); + pcNew[i] = pcNor.NormalizeSafe(); } } diff --git a/code/GenVertexNormalsProcess.h b/code/GenVertexNormalsProcess.h index 6904ae253..a639b6ce1 100644 --- a/code/GenVertexNormalsProcess.h +++ b/code/GenVertexNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenericProperty.h b/code/GenericProperty.h index 77994c0b6..5d9dff3f3 100644 --- a/code/GenericProperty.h +++ b/code/GenericProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/HMPFileData.h b/code/HMPFileData.h index 35b80d25f..cff3b6b18 100644 --- a/code/HMPFileData.h +++ b/code/HMPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/HMPLoader.cpp b/code/HMPLoader.cpp index 3ca84bbe6..5be54110f 100644 --- a/code/HMPLoader.cpp +++ b/code/HMPLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/HMPLoader.h b/code/HMPLoader.h index 5b6b1df74..9d5c77831 100644 --- a/code/HMPLoader.h +++ b/code/HMPLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/HalfLifeFileData.h b/code/HalfLifeFileData.h index 82eba0adc..54fe83734 100644 --- a/code/HalfLifeFileData.h +++ b/code/HalfLifeFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Hash.h b/code/Hash.h index 5ba08ca56..cd7ca6def 100644 --- a/code/Hash.h +++ b/code/Hash.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCCurve.cpp b/code/IFCCurve.cpp index 09becc617..5b1a939b9 100644 --- a/code/IFCCurve.cpp +++ b/code/IFCCurve.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCLoader.cpp b/code/IFCLoader.cpp index 939b9f081..3cd8c7338 100644 --- a/code/IFCLoader.cpp +++ b/code/IFCLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCLoader.h b/code/IFCLoader.h index 703c8b392..e301a329d 100644 --- a/code/IFCLoader.h +++ b/code/IFCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCMaterial.cpp b/code/IFCMaterial.cpp index e603b3cba..d1954a88c 100644 --- a/code/IFCMaterial.cpp +++ b/code/IFCMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCProfile.cpp b/code/IFCProfile.cpp index f97217e44..c2bf91c56 100644 --- a/code/IFCProfile.cpp +++ b/code/IFCProfile.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCUtil.cpp b/code/IFCUtil.cpp index 55a30a878..233d52d0b 100644 --- a/code/IFCUtil.cpp +++ b/code/IFCUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCUtil.h b/code/IFCUtil.h index 386b43031..ba0474c0a 100644 --- a/code/IFCUtil.h +++ b/code/IFCUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index e325e1409..5558188ec 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -196,7 +196,7 @@ void IRRImporter::BuildSkybox(std::vector& meshes, std::vectorAddProperty(&s,AI_MATKEY_NAME); int shading = aiShadingMode_NoShading; @@ -347,7 +347,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNodeName.length = ::sprintf(anim->mNodeName.data, + anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, MAXLEN, "$INST_DUMMY_%i_%s",total-1, (root->name.length() ? root->name.c_str() : "")); diff --git a/code/IRRLoader.h b/code/IRRLoader.h index 04a65a24b..e3ad849d3 100644 --- a/code/IRRLoader.h +++ b/code/IRRLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "IRRShared.h" #include "SceneCombiner.h" #include "Importer.h" +#include "StringUtils.h" #include "../include/assimp/anim.h" namespace Assimp { @@ -113,7 +114,7 @@ private: } type; - Animator(AT t = UNKNOWN) + explicit Animator(AT t = UNKNOWN) : type (t) , speed (0.001f) , direction (0.f,1.f,0.f) @@ -163,7 +164,7 @@ private: ANIMMESH } type; - Node(ET t) + explicit Node(ET t) : type (t) , scaling (1.f,1.f,1.f) // assume uniform scaling by default , parent() @@ -177,7 +178,7 @@ private: // Generate a default name for the node char buffer[128]; static int cnt; - ::sprintf(buffer,"IrrNode_%i",cnt++); + ai_snprintf(buffer, 128, "IrrNode_%i",cnt++); name = std::string(buffer); // reserve space for up to 5 materials diff --git a/code/IRRMeshLoader.cpp b/code/IRRMeshLoader.cpp index 3a00fbe86..b6b6f2bdc 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/IRRMeshLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/IRRMeshLoader.h b/code/IRRMeshLoader.h index 9745d192f..13827d073 100644 --- a/code/IRRMeshLoader.h +++ b/code/IRRMeshLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IRRShared.cpp b/code/IRRShared.cpp index 1d5343d43..9feec3354 100644 --- a/code/IRRShared.cpp +++ b/code/IRRShared.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/Importer.cpp b/code/Importer.cpp index c30ffc2cf..b0325570f 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -90,6 +90,8 @@ using namespace Assimp::Formatter; namespace Assimp { // ImporterRegistry.cpp void GetImporterInstanceList(std::vector< BaseImporter* >& out); + void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); + // PostStepRegistry.cpp void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); } @@ -140,7 +142,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { // ------------------------------------------------------------------------------------------------ // Importer constructor. Importer::Importer() -{ + : pimpl( NULL ) { // allocate the pimpl first pimpl = new ImporterPimpl(); @@ -173,8 +175,7 @@ Importer::Importer() Importer::~Importer() { // Delete all import plugins - for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) - delete pimpl->mImporter[a]; + DeleteImporterInstanceList(pimpl->mImporter); // Delete all post-processing plug-ins for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) @@ -197,7 +198,7 @@ Importer::~Importer() // ------------------------------------------------------------------------------------------------ // Copy constructor - copies the config of another Importer, not the scene Importer::Importer(const Importer &other) -{ + : pimpl(NULL) { new(this) Importer(); pimpl->mIntProperties = other.pimpl->mIntProperties; @@ -491,7 +492,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, pHint = ""; } - if (!pBuffer || !pLength || strlen(pHint) > 100) { + if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; return NULL; } @@ -503,8 +504,9 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength)); // read the file and recover the previous IOSystem - char fbuff[128]; - sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); + static const size_t BufferSize(Importer::MaxLenHint + 28); + char fbuff[ BufferSize ]; + ai_snprintf(fbuff, BufferSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); ReadFile(fbuff,pFlags); SetIOHandler(io); @@ -831,6 +833,80 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) return pimpl->mScene; } +// ------------------------------------------------------------------------------------------------ +const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { + ASSIMP_BEGIN_EXCEPTION_REGION(); + + // Return immediately if no scene is active + if ( NULL == pimpl->mScene ) { + return NULL; + } + + // If no flags are given, return the current scene with no further action + if ( NULL == rootProcess ) { + return pimpl->mScene; + } + + // In debug builds: run basic flag validation + DefaultLogger::get()->info( "Entering customized post processing pipeline" ); + +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS + // The ValidateDS process plays an exceptional role. It isn't contained in the global + // list of post-processing steps, so we need to call it manually. + if ( requestValidation ) + { + ValidateDSProcess ds; + ds.ExecuteOnScene( this ); + if ( !pimpl->mScene ) { + return NULL; + } + } +#endif // no validation +#ifdef ASSIMP_BUILD_DEBUG + if ( pimpl->bExtraVerbose ) + { +#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS + DefaultLogger::get()->error( "Verbose Import is not available due to build settings" ); +#endif // no validation + } +#else + if ( pimpl->bExtraVerbose ) { + DefaultLogger::get()->warn( "Not a debug build, ignoring extra verbose setting" ); + } +#endif // ! DEBUG + + boost::scoped_ptr profiler( GetPropertyInteger( AI_CONFIG_GLOB_MEASURE_TIME, 0 ) ? new Profiler() : NULL ); + + if ( profiler ) { + profiler->BeginRegion( "postprocess" ); + } + + rootProcess->ExecuteOnScene( this ); + + if ( profiler ) { + profiler->EndRegion( "postprocess" ); + } + + // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step + if ( pimpl->bExtraVerbose || requestValidation ) { + DefaultLogger::get()->debug( "Verbose Import: revalidating data structures" ); + + ValidateDSProcess ds; + ds.ExecuteOnScene( this ); + if ( !pimpl->mScene ) { + DefaultLogger::get()->error( "Verbose Import: failed to revalidate data structures" ); + } + } + + // clear any data allocated by post-process steps + pimpl->mPPShared->Clean(); + DefaultLogger::get()->info( "Leaving customized post processing pipeline" ); + + ASSIMP_END_EXCEPTION_REGION( const aiScene* ); + + return pimpl->mScene; +} + // ------------------------------------------------------------------------------------------------ // Helper function to check whether an extension is supported by ASSIMP bool Importer::IsExtensionSupported(const char* szExtension) const @@ -1112,4 +1188,3 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const } in.total += in.materials; } - diff --git a/code/Importer.h b/code/Importer.h index fbf9826ea..7e21327ce 100644 --- a/code/Importer.h +++ b/code/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -167,7 +167,7 @@ public: // ------------------------------------------------------------------- /** Construct a batch loader from a given IO system to be used * to acess external files */ - BatchLoader(IOSystem* pIO); + explicit BatchLoader(IOSystem* pIO); ~BatchLoader(); diff --git a/code/ImporterRegistry.cpp b/code/ImporterRegistry.cpp index 289587b04..380028f07 100644 --- a/code/ImporterRegistry.cpp +++ b/code/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -101,6 +101,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_RAW_IMPORTER # include "RawLoader.h" #endif +#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER +# include "SIBImporter.h" +#endif #ifndef ASSIMP_BUILD_NO_OFF_IMPORTER # include "OFFLoader.h" #endif @@ -170,7 +173,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER # include "AssbinLoader.h" #endif - +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER +# include "glTFImporter.h" +#endif #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER # include "C4DImporter.h" #endif @@ -236,6 +241,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER) out.push_back( new RAWImporter()); #endif +#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER) + out.push_back( new SIBImporter()); +#endif #if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER) out.push_back( new OFFImporter()); #endif @@ -305,10 +313,20 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER ) out.push_back( new AssbinImporter() ); #endif - -#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER +#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER ) + out.push_back( new glTFImporter() ); +#endif +#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER ) out.push_back( new C4DImporter() ); #endif } +/** will delete all registered importers. */ +void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){ + for(size_t i= 0; iinfo(szBuff); @@ -182,7 +183,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh // the JoinIdenticalVertices process has not been executed on this // mesh, otherwise this value would normally be at least minimally // smaller than 3.0 ... - sprintf(szBuff,"Mesh %u: Not suitable for vcache optimization",meshNum); + ai_snprintf(szBuff,128,"Mesh %u: Not suitable for vcache optimization",meshNum); DefaultLogger::get()->warn(szBuff); return 0.f; } @@ -361,7 +362,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh if ( DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { char szBuff[128]; // should be sufficiently large in every case - ::sprintf(szBuff,"Mesh %u | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2, + ai_snprintf(szBuff,128,"Mesh %u | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2, ((fACMR - fACMR2) / fACMR) * 100.f); DefaultLogger::get()->debug(szBuff); } diff --git a/code/ImproveCacheLocality.h b/code/ImproveCacheLocality.h index 336aee582..5523ab2bb 100644 --- a/code/ImproveCacheLocality.h +++ b/code/ImproveCacheLocality.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index b9595bddf..7874d97e7 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -102,7 +102,7 @@ void JoinVerticesProcess::Execute( aiScene* pScene) } else { char szBuff[128]; // should be sufficiently large in every case - sprintf(szBuff,"JoinVerticesProcess finished | Verts in: %i out: %i | ~%.1f%%", + ::ai_snprintf(szBuff,128,"JoinVerticesProcess finished | Verts in: %i out: %i | ~%.1f%%", iNumOldVertices, iNumVertices, ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f); @@ -357,23 +357,24 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) } // adjust bone vertex weights. - for( int a = 0; a < (int)pMesh->mNumBones; a++) - { + for( int a = 0; a < (int)pMesh->mNumBones; a++) { aiBone* bone = pMesh->mBones[a]; std::vector newWeights; newWeights.reserve( bone->mNumWeights); - for( unsigned int b = 0; b < bone->mNumWeights; b++) - { - const aiVertexWeight& ow = bone->mWeights[b]; - // if the vertex is a unique one, translate it - if( !(replaceIndex[ow.mVertexId] & 0x80000000)) - { - aiVertexWeight nw; - nw.mVertexId = replaceIndex[ow.mVertexId]; - nw.mWeight = ow.mWeight; - newWeights.push_back( nw); + if ( NULL != bone->mWeights ) { + for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) { + const aiVertexWeight& ow = bone->mWeights[ b ]; + // if the vertex is a unique one, translate it + if ( !( replaceIndex[ ow.mVertexId ] & 0x80000000 ) ) { + aiVertexWeight nw; + nw.mVertexId = replaceIndex[ ow.mVertexId ]; + nw.mWeight = ow.mWeight; + newWeights.push_back( nw ); + } } + } else { + DefaultLogger::get()->error( "X-Export: aiBone shall contain weights, but pointer to them is NULL." ); } if (newWeights.size() > 0) { diff --git a/code/JoinVerticesProcess.h b/code/JoinVerticesProcess.h index 4bf5743f1..cad66ac9b 100644 --- a/code/JoinVerticesProcess.h +++ b/code/JoinVerticesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp index afef9b76f..9f23c13b2 100644 --- a/code/LWOAnimation.cpp +++ b/code/LWOAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -328,7 +328,12 @@ void AnimResolver::DoInterpolation2(std::vector::const_iterator beg, break; } // linear interpolation - default - fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / ((*end).time - (*beg).time))); + double duration = (*end).time - (*beg).time; + if (duration > 0.0) { + fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / duration)); + } else { + fill = (*beg).value; + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/LWOAnimation.h b/code/LWOAnimation.h index e80634f6f..34dc5e480 100644 --- a/code/LWOAnimation.h +++ b/code/LWOAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOBLoader.cpp b/code/LWOBLoader.cpp index 372100df3..5f2519d8d 100644 --- a/code/LWOBLoader.cpp +++ b/code/LWOBLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/LWOFileData.h b/code/LWOFileData.h index 5838b5026..9f69bdd5f 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -269,7 +269,7 @@ struct Face : public aiFace {} //! Construction from given type - Face(uint32_t _type) + explicit Face(uint32_t _type) : surfaceIndex (0) , smoothGroup (0) , type (_type) @@ -305,7 +305,7 @@ struct Face : public aiFace */ struct VMapEntry { - VMapEntry(unsigned int _dims) + explicit VMapEntry(unsigned int _dims) : dims(_dims) {} diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index 8de88055b..86846cf62 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -1167,7 +1167,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) std::ostringstream ss; GetS0(s,head.length); - head.length -= (unsigned int)s.length()+1; + head.length -= (uint16_t)s.length()+1; ss << s; ss << std::setw(digits) << offset + start; GetS0(s,head.length); @@ -1370,7 +1370,7 @@ void LWOImporter::LoadLWO2File() // if the name is empty, generate a default name if (layer.mName.empty()) { char buffer[128]; // should be sufficiently large - ::sprintf(buffer,"Layer_%i", iUnnamed++); + ::ai_snprintf(buffer, 128, "Layer_%i", iUnnamed++); layer.mName = buffer; } diff --git a/code/LWOLoader.h b/code/LWOLoader.h index c1eed0843..b0bcc35dc 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index 71fda6ce2..7513032ee 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -457,7 +457,7 @@ void LWOImporter::FindUVChannels(LWO::Surface& surf, ++extra; out[next++] = i; } - // Bäh ... seems not to be used at all. Push to end if enough space is available. + // B�h ... seems not to be used at all. Push to end if enough space is available. else { out[extra++] = i; ++num_extra; diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index 95f90ca80..e9c39d1b6 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -323,11 +323,11 @@ void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src) else ++s; std::string::size_type t = src.path.substr(s).find_last_of("."); - nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined); + nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined); return; } } - nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.name,combined); + nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.name,combined); } // ------------------------------------------------------------------------------------------------ diff --git a/code/LWSLoader.h b/code/LWSLoader.h index b31b815ee..9547b67bb 100644 --- a/code/LWSLoader.h +++ b/code/LWSLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LimitBoneWeightsProcess.cpp b/code/LimitBoneWeightsProcess.cpp index a0d88db68..23990272f 100644 --- a/code/LimitBoneWeightsProcess.cpp +++ b/code/LimitBoneWeightsProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "LimitBoneWeightsProcess.h" +#include "StringUtils.h" #include "../include/assimp/postprocess.h" #include "../include/assimp/DefaultLogger.hpp" #include "../include/assimp/scene.h" @@ -193,7 +194,7 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) if (!DefaultLogger::isNullLogger()) { char buffer[1024]; - ::sprintf(buffer,"Removed %u weights. Input bones: %u. Output bones: %u",removed,old_bones,pMesh->mNumBones); + ai_snprintf(buffer,1024,"Removed %u weights. Input bones: %u. Output bones: %u",removed,old_bones,pMesh->mNumBones); DefaultLogger::get()->info(buffer); } } diff --git a/code/LimitBoneWeightsProcess.h b/code/LimitBoneWeightsProcess.h index d683d0be9..2f07bfeba 100644 --- a/code/LimitBoneWeightsProcess.h +++ b/code/LimitBoneWeightsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LineSplitter.h b/code/LineSplitter.h index b517bd2be..0fa47380e 100644 --- a/code/LineSplitter.h +++ b/code/LineSplitter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -83,7 +83,8 @@ public: note: trim is *always* assumed true if skyp_empty_lines==true */ LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true) - : stream(stream) + : idx( 0 ) + , stream(stream) , swallow() , skip_empty_lines(skip_empty_lines) , trim(trim) @@ -94,6 +95,10 @@ public: idx = 0; } + ~LineSplitter() { + // empty + } + public: // ----------------------------------------- @@ -227,7 +232,10 @@ public: } private: + LineSplitter( const LineSplitter & ); + LineSplitter &operator = ( const LineSplitter & ); +private: line_idx idx; std::string cur; StreamReaderLE& stream; diff --git a/code/LogAux.h b/code/LogAux.h index f829f6204..4b0c59cd1 100644 --- a/code/LogAux.h +++ b/code/LogAux.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD2FileData.h b/code/MD2FileData.h index e103c0b1c..4bb5db4ca 100644 --- a/code/MD2FileData.h +++ b/code/MD2FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index f7adf731a..4b7bbe67a 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/MD2Loader.h b/code/MD2Loader.h index ea52d7461..05acc3ae0 100644 --- a/code/MD2Loader.h +++ b/code/MD2Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD2NormalTable.h b/code/MD2NormalTable.h index 6cb0d88ee..5b1344bd6 100644 --- a/code/MD2NormalTable.h +++ b/code/MD2NormalTable.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD3FileData.h b/code/MD3FileData.h index 9fd40ed97..97043bc11 100644 --- a/code/MD3FileData.h +++ b/code/MD3FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index 3852a64a2..93ccc4ad1 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/MD3Loader.h b/code/MD3Loader.h index edf801b9f..e5e7dcc07 100644 --- a/code/MD3Loader.h +++ b/code/MD3Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index 6f0780e6d..45eba1253 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -735,7 +735,7 @@ void MD5Importer::LoadMD5CameraFile () for (std::vector::const_iterator it = cuts.begin(); it != cuts.end()-1; ++it) { aiAnimation* anim = *tmp++ = new aiAnimation(); - anim->mName.length = ::sprintf(anim->mName.data,"anim%u_from_%u_to_%u",(unsigned int)(it-cuts.begin()),(*it),*(it+1)); + anim->mName.length = ::ai_snprintf(anim->mName.data, MAXLEN, "anim%u_from_%u_to_%u",(unsigned int)(it-cuts.begin()),(*it),*(it+1)); anim->mTicksPerSecond = cameraParser.fFrameRate; anim->mChannels = new aiNodeAnim*[anim->mNumChannels = 1]; diff --git a/code/MD5Loader.h b/code/MD5Loader.h index c809a99f7..9683f6751 100644 --- a/code/MD5Loader.h +++ b/code/MD5Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD5Parser.cpp b/code/MD5Parser.cpp index 05e154cc6..101c52d1d 100644 --- a/code/MD5Parser.cpp +++ b/code/MD5Parser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -85,7 +85,7 @@ MD5Parser::MD5Parser(char* _buffer, unsigned int _fileSize ) if ( !DefaultLogger::isNullLogger()) { char szBuffer[128]; // should be sufficiently large - ::sprintf(szBuffer,"MD5Parser end. Parsed %i sections",(int)mSections.size()); + ::ai_snprintf(szBuffer,128,"MD5Parser end. Parsed %i sections",(int)mSections.size()); DefaultLogger::get()->debug(szBuffer); } } @@ -95,7 +95,7 @@ MD5Parser::MD5Parser(char* _buffer, unsigned int _fileSize ) /*static*/ AI_WONT_RETURN void MD5Parser::ReportError (const char* error, unsigned int line) { char szBuffer[1024]; - ::sprintf(szBuffer,"[MD5] Line %u: %s",line,error); + ::ai_snprintf(szBuffer, 1024, "[MD5] Line %u: %s",line,error); throw DeadlyImportError(szBuffer); } diff --git a/code/MD5Parser.h b/code/MD5Parser.h index e08d6d8b4..bbc844d57 100644 --- a/code/MD5Parser.h +++ b/code/MD5Parser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -280,7 +280,7 @@ public: * * @param mSections List of file sections (output of MD5Parser) */ - MD5MeshParser(SectionList& mSections); + explicit MD5MeshParser(SectionList& mSections); //! List of all meshes MeshList mMeshes; @@ -305,7 +305,7 @@ public: * * @param mSections List of file sections (output of MD5Parser) */ - MD5AnimParser(SectionList& mSections); + explicit MD5AnimParser(SectionList& mSections); //! Output frame rate @@ -337,7 +337,7 @@ public: * * @param mSections List of file sections (output of MD5Parser) */ - MD5CameraParser(SectionList& mSections); + explicit MD5CameraParser(SectionList& mSections); //! Output frame rate diff --git a/code/MDCFileData.h b/code/MDCFileData.h index ba5789e0f..da6735a3e 100644 --- a/code/MDCFileData.h +++ b/code/MDCFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDCLoader.cpp b/code/MDCLoader.cpp index a207439cf..a12c8c29c 100644 --- a/code/MDCLoader.cpp +++ b/code/MDCLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/MDCLoader.h b/code/MDCLoader.h index 6a1c77975..3cadc4ae4 100644 --- a/code/MDCLoader.h +++ b/code/MDCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLDefaultColorMap.h b/code/MDLDefaultColorMap.h index 621b5b220..6db696af0 100644 --- a/code/MDLDefaultColorMap.h +++ b/code/MDLDefaultColorMap.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLFileData.h b/code/MDLFileData.h index c2bae9086..536bf082a 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLLoader.cpp b/code/MDLLoader.cpp index c5b8d63c3..957aa1be2 100644 --- a/code/MDLLoader.cpp +++ b/code/MDLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MDLLoader.h" #include "MDLDefaultColorMap.h" #include "MD2FileData.h" +#include "StringUtils.h" #include "../include/assimp/Importer.hpp" #include #include "../include/assimp/IOSystem.hpp" @@ -942,7 +943,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) { // no real name for our poor bone is specified :-( - pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data, + pcOutBone->mName.length = ai_snprintf(pcOutBone->mName.data, MAXLEN, "UnnamedBone_%i",iBone); } else { @@ -1384,7 +1385,8 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) avOutList[i].reserve(3); // buffer to held the names of all groups in the file - char* aszGroupNameBuffer = new char[AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num]; + const size_t buffersize( AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num ); + char* aszGroupNameBuffer = new char[ buffersize ]; // read all groups for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) { @@ -1544,9 +1546,12 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // setup the name of the node char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE]; - if ('\0' == *szBuffer) - pcNode->mName.length = ::sprintf(szBuffer,"Group_%u",p); - else pcNode->mName.length = ::strlen(szBuffer); + if ('\0' == *szBuffer) { + const size_t maxSize(buffersize - (i*AI_MDL7_MAX_GROUPNAMESIZE)); + pcNode->mName.length = ai_snprintf(szBuffer, maxSize, "Group_%u", p); + } else { + pcNode->mName.length = ::strlen(szBuffer); + } ::strcpy(pcNode->mName.data,szBuffer); ++p; } diff --git a/code/MDLLoader.h b/code/MDLLoader.h index 15ef1fc1d..62e451cbe 100644 --- a/code/MDLLoader.h +++ b/code/MDLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLMaterialLoader.cpp b/code/MDLMaterialLoader.cpp index 459156f66..455f1e6d0 100644 --- a/code/MDLMaterialLoader.cpp +++ b/code/MDLMaterialLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "MDLLoader.h" #include "MDLDefaultColorMap.h" +#include "StringUtils.h" #include "../include/assimp/texture.h" #include "../include/assimp/IOSystem.hpp" #include "../include/assimp/DefaultLogger.hpp" @@ -699,7 +700,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7( // place this as diffuse texture char szCurrent[5]; - ::sprintf(szCurrent,"*%i",this->pScene->mNumTextures); + ai_snprintf(szCurrent,5,"*%i",this->pScene->mNumTextures); aiString szFile; const size_t iLen = strlen((const char*)szCurrent); diff --git a/code/MS3DLoader.cpp b/code/MS3DLoader.cpp index 1aff8286a..6a0d21be8 100644 --- a/code/MS3DLoader.cpp +++ b/code/MS3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/MS3DLoader.h b/code/MS3DLoader.h index 14f30c70f..22d12e3cf 100644 --- a/code/MS3DLoader.h +++ b/code/MS3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MakeVerboseFormat.cpp b/code/MakeVerboseFormat.cpp index 03f9c074d..451a61635 100644 --- a/code/MakeVerboseFormat.cpp +++ b/code/MakeVerboseFormat.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -172,13 +172,15 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) for (unsigned int i = 0;i < pcMesh->mNumBones;++i) { delete pcMesh->mBones[i]->mWeights; - if (!newWeights[i].empty()) - { + if (!newWeights[i].empty()) { pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()]; - memcpy(pcMesh->mBones[i]->mWeights,&newWeights[i][0], + aiVertexWeight *weightToCopy = &( newWeights[i][0] ); + memcpy(pcMesh->mBones[i]->mWeights, weightToCopy, sizeof(aiVertexWeight) * newWeights[i].size()); + delete[] newWeights; + } else { + pcMesh->mBones[i]->mWeights = NULL; } - else pcMesh->mBones[i]->mWeights = NULL; } // delete the old members diff --git a/code/MakeVerboseFormat.h b/code/MakeVerboseFormat.h index 2e28bfc95..1b32cf19e 100644 --- a/code/MakeVerboseFormat.h +++ b/code/MakeVerboseFormat.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MaterialSystem.cpp b/code/MaterialSystem.cpp index aa17d5458..02f971737 100644 --- a/code/MaterialSystem.cpp +++ b/code/MaterialSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,7 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/assimp/DefaultLogger.hpp" #include "Macros.h" - using namespace Assimp; // ------------------------------------------------------------------------------------------------ @@ -571,9 +570,11 @@ void aiMaterial::CopyPropertyList(aiMaterial* pcDest, for (unsigned int i = 0; i < iOldNum;++i) { pcDest->mProperties[i] = pcOld[i]; } - - delete[] pcOld; } + + if(pcOld) + delete[] pcOld; + for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) { aiMaterialProperty* propSrc = pcSrc->mProperties[i]; @@ -605,4 +606,3 @@ void aiMaterial::CopyPropertyList(aiMaterial* pcDest, } return; } - diff --git a/code/MaterialSystem.h b/code/MaterialSystem.h index 790708078..6726e0518 100644 --- a/code/MaterialSystem.h +++ b/code/MaterialSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MemoryIOWrapper.h b/code/MemoryIOWrapper.h index 1fc8b2a29..acd6d8633 100644 --- a/code/MemoryIOWrapper.h +++ b/code/MemoryIOWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -178,7 +178,8 @@ public: // ------------------------------------------------------------------- /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* /*pFile*/) { + void Close( IOStream* pFile) { + delete pFile; } // ------------------------------------------------------------------- diff --git a/code/NDOLoader.cpp b/code/NDOLoader.cpp index 40daa5717..36cc2323b 100644 --- a/code/NDOLoader.cpp +++ b/code/NDOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/NFFLoader.cpp b/code/NFFLoader.cpp index c96b7b1c4..029e9b87d 100644 --- a/code/NFFLoader.cpp +++ b/code/NFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -862,7 +862,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // generate a name for the mesh - ::sprintf(currentMesh.name,"sphere_%i",sphere++); + ::ai_snprintf(currentMesh.name,128,"sphere_%i",sphere++); } // 'dod' - dodecahedron else if (TokenMatch(sz,"dod",3)) @@ -879,7 +879,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // generate a name for the mesh - ::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++); + ::ai_snprintf(currentMesh.name,128,"dodecahedron_%i",dodecahedron++); } // 'oct' - octahedron @@ -897,7 +897,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // generate a name for the mesh - ::sprintf(currentMesh.name,"octahedron_%i",octahedron++); + ::ai_snprintf(currentMesh.name,128,"octahedron_%i",octahedron++); } // 'tet' - tetrahedron @@ -915,7 +915,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // generate a name for the mesh - ::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++); + ::ai_snprintf(currentMesh.name,128,"tetrahedron_%i",tetrahedron++); } // 'hex' - hexahedron @@ -933,7 +933,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // generate a name for the mesh - ::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++); + ::ai_snprintf(currentMesh.name,128,"hexahedron_%i",hexahedron++); } // 'c' - cone else if (TokenMatch(sz,"c",1)) @@ -988,8 +988,8 @@ void NFFImporter::InternReadFile( const std::string& pFile, // generate a name for the mesh. 'cone' if it a cone, // 'cylinder' if it is a cylinder. Funny, isn't it? if (radius1 != radius2) - ::sprintf(currentMesh.name,"cone_%i",cone++); - else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++); + ::ai_snprintf(currentMesh.name,128,"cone_%i",cone++); + else ::ai_snprintf(currentMesh.name,128,"cylinder_%i",cylinder++); } // 'tess' - tesselation else if (TokenMatch(sz,"tess",4)) @@ -1115,7 +1115,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, aiNode* nd = *ppcChildren = new aiNode(); nd->mParent = root; - nd->mName.length = ::sprintf(nd->mName.data,"",i); + nd->mName.length = ::ai_snprintf(nd->mName.data,1024,"",i); // allocate the light in the scene data structure aiLight* out = pScene->mLights[i] = new aiLight(); @@ -1139,8 +1139,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, mesh->mNumFaces = (unsigned int)src.faces.size(); // Generate sub nodes for named meshes - if (src.name[0]) - { + if ( src.name[ 0 ] && NULL != ppcChildren ) { aiNode* const node = *ppcChildren = new aiNode(); node->mParent = root; node->mNumMeshes = 1; @@ -1161,8 +1160,9 @@ void NFFImporter::InternReadFile( const std::string& pFile, mat.c4 = src.center.z; ++ppcChildren; - } - else *pMeshes++ = m; + } else { + *pMeshes++ = m; + } // copy vertex positions mesh->mVertices = new aiVector3D[mesh->mNumVertices]; diff --git a/code/NFFLoader.h b/code/NFFLoader.h index e168548f0..5339cbe78 100644 --- a/code/NFFLoader.h +++ b/code/NFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OFFLoader.cpp b/code/OFFLoader.cpp index d5c23dcfa..47ce106cf 100644 --- a/code/OFFLoader.cpp +++ b/code/OFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -138,9 +138,15 @@ void OFFImporter::InternReadFile( const std::string& pFile, throw DeadlyImportError("OFF: There are no valid faces"); } - pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ]; - aiMesh* mesh = pScene->mMeshes[0] = new aiMesh(); - aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces]; + pScene->mNumMeshes = 1; + pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; + + aiMesh* mesh = new aiMesh(); + pScene->mMeshes[0] = mesh; + + mesh->mNumFaces = numFaces; + aiFace* faces = new aiFace [mesh->mNumFaces]; + mesh->mFaces = faces; std::vector tempPositions(numVertices); @@ -171,7 +177,8 @@ void OFFImporter::InternReadFile( const std::string& pFile, break; } sz = line;SkipSpaces(&sz); - if(!(faces->mNumIndices = strtoul10(sz,&sz)) || faces->mNumIndices > 9) + faces->mNumIndices = strtoul10(sz,&sz); + if(!(faces->mNumIndices) || faces->mNumIndices > 9) { DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed"); --mesh->mNumFaces; @@ -185,43 +192,54 @@ void OFFImporter::InternReadFile( const std::string& pFile, throw DeadlyImportError("OFF: There are no valid faces"); // allocate storage for the output vertices - aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + std::vector verts; + verts.reserve(mesh->mNumVertices); // second: now parse all face indices - buffer = old;faces = mesh->mFaces; + buffer = old; + faces = mesh->mFaces; for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;) { if(!GetNextLine(buffer,line))break; unsigned int idx; sz = line;SkipSpaces(&sz); - if(!(idx = strtoul10(sz,&sz)) || idx > 9) + idx = strtoul10(sz,&sz); + if(!(idx) || idx > 9) continue; faces->mIndices = new unsigned int [faces->mNumIndices]; for (unsigned int m = 0; m < faces->mNumIndices;++m) { SkipSpaces(&sz); - if ((idx = strtoul10(sz,&sz)) >= numVertices) + idx = strtoul10(sz,&sz); + if ((idx) >= numVertices) { DefaultLogger::get()->error("OFF: Vertex index is out of range"); idx = numVertices-1; } faces->mIndices[m] = p++; - *verts++ = tempPositions[idx]; + verts.push_back(tempPositions[idx]); } ++i; ++faces; } + if (mesh->mNumVertices != verts.size()) { + throw DeadlyImportError("OFF: Vertex count mismatch"); + } + mesh->mVertices = new aiVector3D[verts.size()]; + memcpy(mesh->mVertices, &verts[0], verts.size() * sizeof(aiVector3D)); // generate the output node graph pScene->mRootNode = new aiNode(); pScene->mRootNode->mName.Set(""); - pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes = 1]; + pScene->mRootNode->mNumMeshes = 1; + pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes]; pScene->mRootNode->mMeshes[0] = 0; // generate a default material - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = 1]; + pScene->mNumMaterials = 1; + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; aiMaterial* pcMat = new aiMaterial(); aiColor4D clr(0.6f,0.6f,0.6f,1.0f); diff --git a/code/OFFLoader.h b/code/OFFLoader.h index 3d294c64f..a4f38c3ae 100644 --- a/code/OFFLoader.h +++ b/code/OFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index 5e3d2d7fd..4cfdb37e5 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjExporter.h b/code/ObjExporter.h index 0a1252d0b..9d817f067 100644 --- a/code/ObjExporter.h +++ b/code/ObjExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjFileData.h b/code/ObjFileData.h index 9aa44576b..370d0e4fb 100644 --- a/code/ObjFileData.h +++ b/code/ObjFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -242,7 +242,7 @@ struct Mesh { bool m_hasNormals; /// Constructor - Mesh( const std::string &name ) + explicit Mesh( const std::string &name ) : m_name( name ) , m_pMaterial(NULL) , m_uiNumIndices(0) diff --git a/code/ObjFileImporter.cpp b/code/ObjFileImporter.cpp index ebf75b3c4..c812baf23 100644 --- a/code/ObjFileImporter.cpp +++ b/code/ObjFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -114,37 +114,43 @@ const aiImporterDesc* ObjFileImporter::GetInfo () const // ------------------------------------------------------------------------------------------------ // Obj-file import implementation -void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) -{ +void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) { // Read file into memory - const std::string mode = "rb"; - boost::scoped_ptr file( pIOHandler->Open( pFile, mode)); - if( !file.get() ) { - throw DeadlyImportError( "Failed to open file " + pFile + "." ); + static const std::string mode = "rb"; + boost::scoped_ptr fileStream( pIOHandler->Open( file, mode)); + if( !fileStream.get() ) { + throw DeadlyImportError( "Failed to open file " + file + "." ); } // Get the file-size and validate it, throwing an exception when fails - size_t fileSize = file->FileSize(); + size_t fileSize = fileStream->FileSize(); if( fileSize < ObjMinSize ) { throw DeadlyImportError( "OBJ-file is too small."); } // Allocate buffer and read file into it - TextFileToBuffer(file.get(),m_Buffer); + TextFileToBuffer( fileStream.get(),m_Buffer); // Get the model name std::string modelName, folderName; - std::string::size_type pos = pFile.find_last_of( "\\/" ); + std::string::size_type pos = file.find_last_of( "\\/" ); if ( pos != std::string::npos ) { - modelName = pFile.substr(pos+1, pFile.size() - pos - 1); - folderName = pFile.substr( 0, pos ); - if ( folderName.empty() ) { + modelName = file.substr(pos+1, file.size() - pos - 1); + folderName = file.substr( 0, pos ); + if ( !folderName.empty() ) { pIOHandler->PushDirectory( folderName ); } } else { - modelName = pFile; + modelName = file; } + // This next stage takes ~ 1/3th of the total readFile task + // so should amount for 1/3th of the progress + // only update every 100KB or it'll be too slow + unsigned int progress = 0; + unsigned int progressCounter = 0; + const unsigned int updateProgressEveryBytes = 100 * 1024; + const unsigned int progressTotal = (3*m_Buffer.size()/updateProgressEveryBytes); // process all '\' std::vector ::iterator iter = m_Buffer.begin(); while (iter != m_Buffer.end()) @@ -159,10 +165,19 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, } else ++iter; + + if (++progressCounter >= updateProgressEveryBytes) + { + m_progress->UpdateFileRead(++progress, progressTotal); + progressCounter = 0; + } } + // 1/3rd progress + m_progress->UpdateFileRead(1, 3); + // parse the file into a temporary representation - ObjFileParser parser(m_Buffer, modelName, pIOHandler); + ObjFileParser parser(m_Buffer, modelName, pIOHandler, m_progress); // And create the proper return structures out of it CreateDataFromImport(parser.GetModel(), pScene); diff --git a/code/ObjFileImporter.h b/code/ObjFileImporter.h index a0af3a689..37420406c 100644 --- a/code/ObjFileImporter.h +++ b/code/ObjFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index 5b5160a44..632f928c4 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -87,7 +87,7 @@ static const std::string TypeOption = "-type"; // ------------------------------------------------------------------- // Constructor ObjFileMtlImporter::ObjFileMtlImporter( std::vector &buffer, - const std::string & /*strAbsPath*/, + const std::string &, ObjFile::Model *pModel ) : m_DataIt( buffer.begin() ), m_DataItEnd( buffer.end() ), @@ -112,14 +112,14 @@ ObjFileMtlImporter::~ObjFileMtlImporter() // ------------------------------------------------------------------- // Private copy constructor -ObjFileMtlImporter::ObjFileMtlImporter(const ObjFileMtlImporter & /* rOther */ ) +ObjFileMtlImporter::ObjFileMtlImporter(const ObjFileMtlImporter & ) { // empty } // ------------------------------------------------------------------- // Private copy constructor -ObjFileMtlImporter &ObjFileMtlImporter::operator = ( const ObjFileMtlImporter & /*rOther */ ) +ObjFileMtlImporter &ObjFileMtlImporter::operator = ( const ObjFileMtlImporter & ) { return *this; } @@ -284,6 +284,8 @@ void ObjFileMtlImporter::createMaterial() } } + name = trim_whitespaces(name); + std::map::iterator it = m_pModel->m_MaterialMap.find( name ); if ( m_pModel->m_MaterialMap.end() == it) { // New Material created @@ -337,6 +339,7 @@ void ObjFileMtlImporter::getTexture() { } else if(!ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), ReflectionTexture.size() ) ) { // Reflection texture(s) //Do nothing here + return; } else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), DisplacementTexture.size() ) ) { // Displacement texture out = &m_pModel->m_pCurrentMaterial->textureDisp; @@ -356,7 +359,9 @@ void ObjFileMtlImporter::getTexture() { std::string texture; m_DataIt = getName( m_DataIt, m_DataItEnd, texture ); - out->Set( texture ); + if ( NULL!=out ) { + out->Set( texture ); + } } /* ///////////////////////////////////////////////////////////////////////////// @@ -374,11 +379,10 @@ void ObjFileMtlImporter::getTexture() { * Because aiMaterial supports clamp option, so we also want to return it * ///////////////////////////////////////////////////////////////////////////// */ -void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) -{ +void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) { m_DataIt = getNextToken(m_DataIt, m_DataItEnd); - //If there is any more texture option + // If there is any more texture option while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-') { const char *pPtr( &(*m_DataIt) ); diff --git a/code/ObjFileMtlImporter.h b/code/ObjFileMtlImporter.h index 8bcfc51e1..f2c1ba820 100644 --- a/code/ObjFileMtlImporter.h +++ b/code/ObjFileMtlImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 027d99543..f23cea879 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -61,12 +61,13 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME; // ------------------------------------------------------------------- // Constructor with loaded data and directories. -ObjFileParser::ObjFileParser(std::vector &data,const std::string &modelName, IOSystem *io ) : +ObjFileParser::ObjFileParser(std::vector &data,const std::string &modelName, IOSystem *io, ProgressHandler* progress ) : m_DataIt(data.begin()), m_DataItEnd(data.end()), m_pModel(NULL), m_uiLine(0), - m_pIO( io ) + m_pIO( io ), + m_progress(progress) { std::fill_n(m_buffer,Buffersize,0); @@ -106,8 +107,28 @@ void ObjFileParser::parseFile() if (m_DataIt == m_DataItEnd) return; + // only update every 100KB or it'll be too slow + const unsigned int updateProgressEveryBytes = 100 * 1024; + unsigned int progressCounter = 0; + const unsigned int bytesToProcess = std::distance(m_DataIt, m_DataItEnd); + const unsigned int progressTotal = 3 * bytesToProcess; + const unsigned int progressOffset = bytesToProcess; + unsigned int processed = 0; + + DataArrayIt lastDataIt = m_DataIt; + while (m_DataIt != m_DataItEnd) { + // Handle progress reporting + processed += std::distance(lastDataIt, m_DataIt); + lastDataIt = m_DataIt; + if (processed > (progressCounter * updateProgressEveryBytes)) + { + progressCounter++; + m_progress->UpdateFileRead(progressOffset + processed*2, progressTotal); + } + + // parse line switch (*m_DataIt) { case 'v': // Parse a vertex texture coordinate @@ -272,7 +293,7 @@ void ObjFileParser::getVector( std::vector &point3d_array ) { // ------------------------------------------------------------------- // Get values for a new 3D vector instance -void ObjFileParser::getVector3(std::vector &point3d_array) { +void ObjFileParser::getVector3( std::vector &point3d_array ) { float x, y, z; copyNextWord(m_buffer, Buffersize); x = (float) fast_atof(m_buffer); @@ -302,19 +323,18 @@ void ObjFileParser::getVector2( std::vector &point2d_array ) { m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } +static const std::string DefaultObjName = "defaultobject"; + // ------------------------------------------------------------------- // Get values for a new face instance -void ObjFileParser::getFace(aiPrimitiveType type) -{ +void ObjFileParser::getFace(aiPrimitiveType type) { copyNextLine(m_buffer, Buffersize); - if (m_DataIt == m_DataItEnd) - return; - char *pPtr = m_buffer; char *pEnd = &pPtr[Buffersize]; pPtr = getNextToken(pPtr, pEnd); - if (pPtr == pEnd || *pPtr == '\0') + if ( pPtr == pEnd || *pPtr == '\0' ) { return; + } std::vector *pIndices = new std::vector; std::vector *pTexID = new std::vector; @@ -328,20 +348,18 @@ void ObjFileParser::getFace(aiPrimitiveType type) const bool vt = (!m_pModel->m_TextureCoord.empty()); const bool vn = (!m_pModel->m_Normals.empty()); int iStep = 0, iPos = 0; - while (pPtr != pEnd) - { + while (pPtr != pEnd) { iStep = 1; - if (IsLineEnd(*pPtr)) + if ( IsLineEnd( *pPtr ) ) { break; + } - if (*pPtr=='/' ) - { + if (*pPtr=='/' ) { if (type == aiPrimitiveType_POINT) { DefaultLogger::get()->error("Obj: Separator unexpected in point statement"); } - if (iPos == 0) - { + if (iPos == 0) { //if there are no texture coordinates in the file, but normals if (!vt && vn) { iPos = 1; @@ -349,22 +367,20 @@ void ObjFileParser::getFace(aiPrimitiveType type) } } iPos++; - } - else if( IsSpaceOrNewLine( *pPtr ) ) - { + } else if( IsSpaceOrNewLine( *pPtr ) ) { iPos = 0; - } - else - { + } else { //OBJ USES 1 Base ARRAYS!!!! - const int iVal = atoi( pPtr ); + const int iVal( ::atoi( pPtr ) ); // increment iStep position based off of the sign and # of digits int tmp = iVal; - if (iVal < 0) + if ( iVal < 0 ) { ++iStep; - while ( ( tmp = tmp / 10 )!=0 ) + } + while ( ( tmp = tmp / 10 ) != 0 ) { ++iStep; + } if ( iVal > 0 ) { @@ -414,7 +430,7 @@ void ObjFileParser::getFace(aiPrimitiveType type) if ( pIndices->empty() ) { DefaultLogger::get()->error("Obj: Ignoring empty face"); - // skip line and clean up + // skip line and clean up m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); delete pNormalID; delete pTexID; @@ -434,12 +450,12 @@ void ObjFileParser::getFace(aiPrimitiveType type) // Create a default object, if nothing is there if( NULL == m_pModel->m_pCurrent ) { - createObject( "defaultobject" ); + createObject( DefaultObjName ); } // Assign face to mesh if ( NULL == m_pModel->m_pCurrentMesh ) { - createMesh( "defaultobject" ); + createMesh( DefaultObjName ); } // Store the face @@ -457,15 +473,6 @@ void ObjFileParser::getFace(aiPrimitiveType type) // Get values for a new material description void ObjFileParser::getMaterialDesc() { - // Each material request a new object. - // Sometimes the object is already created (see 'o' tag by example), but it is not initialized ! - // So, we create a new object only if the current on is already initialized ! - if (m_pModel->m_pCurrent != NULL && - ( m_pModel->m_pCurrent->m_Meshes.size() > 1 || - (m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0) ) - ) - m_pModel->m_pCurrent = NULL; - // Get next data for material data m_DataIt = getNextToken(m_DataIt, m_DataItEnd); if (m_DataIt == m_DataItEnd) { @@ -477,25 +484,41 @@ void ObjFileParser::getMaterialDesc() ++m_DataIt; } + // In some cases we should ignore this 'usemtl' command, this variable helps us to do so + bool skip = false; + // Get name std::string strName(pStart, &(*m_DataIt)); - if ( strName.empty()) - return; + strName = trim_whitespaces(strName); + if (strName.empty()) + skip = true; - // Search for material - std::map::iterator it = m_pModel->m_MaterialMap.find( strName ); - if ( it == m_pModel->m_MaterialMap.end() ) { - // Not found, use default material - m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; - DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); - } else { - // Found, using detected material - m_pModel->m_pCurrentMaterial = (*it).second; - if ( needsNewMesh( strName )) + // If the current mesh has the same material, we simply ignore that 'usemtl' command + // There is no need to create another object or even mesh here + if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName)) + skip = true; + + if (!skip) + { + // Search for material + std::map::iterator it = m_pModel->m_MaterialMap.find(strName); + if (it == m_pModel->m_MaterialMap.end()) { - createMesh( strName ); + // Not found, use default material + m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; + DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); + strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str(); } - m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName ); + else + { + // Found, using detected material + m_pModel->m_pCurrentMaterial = (*it).second; + } + + if (needsNewMesh(strName)) + createMesh(strName); + + m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName); } // Skip rest of line @@ -539,7 +562,10 @@ void ObjFileParser::getMaterialLib() const std::string strMatName(pStart, &(*m_DataIt)); std::string absName; if ( m_pIO->StackSize() > 0 ) { - const std::string &path = m_pIO->CurrentDirectory(); + std::string path = m_pIO->CurrentDirectory(); + if ( '/' != *path.rbegin() ) { + path += '/'; + } absName = path + strMatName; } else { absName = strMatName; @@ -552,9 +578,12 @@ void ObjFileParser::getMaterialLib() return; } - // Import material library data from file + // Import material library data from file. + // Some exporters (e.g. Silo) will happily write out empty + // material files if the model doesn't use any materials, so we + // allow that. std::vector buffer; - BaseImporter::TextFileToBuffer( pFile, buffer ); + BaseImporter::TextFileToBuffer( pFile, buffer, BaseImporter::ALLOW_EMPTY ); m_pIO->Close( pFile ); // Importing the material library @@ -746,17 +775,17 @@ void ObjFileParser::createMesh( const std::string &meshName ) // ------------------------------------------------------------------- // Returns true, if a new mesh must be created. -bool ObjFileParser::needsNewMesh( const std::string &rMaterialName ) +bool ObjFileParser::needsNewMesh( const std::string &materialName ) { + // If no mesh data yet if(m_pModel->m_pCurrentMesh == 0) { - // No mesh data yet return true; } bool newMat = false; - int matIdx = getMaterialIndex( rMaterialName ); + int matIdx = getMaterialIndex( materialName ); int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex; - if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) || curMatIdx != matIdx ) + if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx ) { // New material -> only one material per mesh, so we need to create a new // material diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index 66f378f29..e16de49a8 100644 --- a/code/ObjFileParser.h +++ b/code/ObjFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -59,6 +59,7 @@ namespace ObjFile { class ObjFileImporter; class IOSystem; +class ProgressHandler; /// \class ObjFileParser /// \brief Parser for a obj waveform file @@ -71,7 +72,7 @@ public: public: /// \brief Constructor with data array. - ObjFileParser(std::vector &Data,const std::string &strModelName, IOSystem* io); + ObjFileParser(std::vector &Data,const std::string &strModelName, IOSystem* io, ProgressHandler* progress); /// \brief Destructor ~ObjFileParser(); /// \brief Model getter. @@ -139,6 +140,8 @@ private: char m_buffer[Buffersize]; /// Pointer to IO system instance. IOSystem *m_pIO; + //! Pointer to progress handler + ProgressHandler* m_progress; /// Path to the current model }; diff --git a/code/ObjTools.h b/code/ObjTools.h index b5ed12192..311965ce3 100644 --- a/code/ObjTools.h +++ b/code/ObjTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -238,6 +238,14 @@ unsigned int tokenize( const string_type& str, std::vector& tokens, return static_cast( tokens.size() ); } +template +string_type trim_whitespaces(string_type str) +{ + while (!str.empty() && IsSpace(str[0])) str.erase(0); + while (!str.empty() && IsSpace(str[str.length() - 1])) str.erase(str.length() - 1); + return str; +} + } // Namespace Assimp #endif // OBJ_TOOLS_H_INC diff --git a/code/OgreBinarySerializer.cpp b/code/OgreBinarySerializer.cpp index b99ec2b6a..dd0b57c00 100644 --- a/code/OgreBinarySerializer.cpp +++ b/code/OgreBinarySerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreBinarySerializer.h b/code/OgreBinarySerializer.h index e00d1082d..b161da3cc 100644 --- a/code/OgreBinarySerializer.h +++ b/code/OgreBinarySerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index 10db22bb0..2eeca22ae 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreImporter.h b/code/OgreImporter.h index e0f486eea..60140f673 100644 --- a/code/OgreImporter.h +++ b/code/OgreImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreMaterial.cpp b/code/OgreMaterial.cpp index d60f2a447..af34ee54b 100644 --- a/code/OgreMaterial.cpp +++ b/code/OgreMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreParsingUtils.h b/code/OgreParsingUtils.h index e53cb9c38..def3cf733 100644 --- a/code/OgreParsingUtils.h +++ b/code/OgreParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreStructs.cpp b/code/OgreStructs.cpp index 80704c596..62c109ad3 100644 --- a/code/OgreStructs.cpp +++ b/code/OgreStructs.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreStructs.h b/code/OgreStructs.h index a18bac379..23776750c 100644 --- a/code/OgreStructs.h +++ b/code/OgreStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -381,8 +381,8 @@ typedef std::vector VertexAnimationTrackList; class Animation { public: - Animation(Skeleton *parent); - Animation(Mesh *parent); + explicit Animation(Skeleton *parent); + explicit Animation(Mesh *parent); /// Returns the associated vertex data for a track in this animation. /** @note Only valid to call when parent Mesh is set. */ diff --git a/code/OgreXmlSerializer.cpp b/code/OgreXmlSerializer.cpp index b2123d2f3..e9c74cc2f 100644 --- a/code/OgreXmlSerializer.cpp +++ b/code/OgreXmlSerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreXmlSerializer.h b/code/OgreXmlSerializer.h index feb288983..4e9b1d95e 100644 --- a/code/OgreXmlSerializer.h +++ b/code/OgreXmlSerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -69,7 +69,7 @@ public: static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); private: - OgreXmlSerializer(XmlReader *reader) : + explicit OgreXmlSerializer(XmlReader *reader) : m_reader(reader) { } diff --git a/code/OpenGEXExporter.cpp b/code/OpenGEXExporter.cpp index 67c898028..77a60fdfb 100644 --- a/code/OpenGEXExporter.cpp +++ b/code/OpenGEXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2014, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,12 +42,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace OpenGEX { +#ifndef ASSIMP_BUILD_NO_OPENGEX_EXPORTER + OpenGEXExporter::OpenGEXExporter() { } OpenGEXExporter::~OpenGEXExporter() { } +#endif // ASSIMP_BUILD_NO_OPENGEX_EXPORTER -} // Namespace openGEX +} // Namespace OpenGEX } // Namespace Assimp diff --git a/code/OpenGEXExporter.h b/code/OpenGEXExporter.h index f2f5eb54b..ac9d9c860 100644 --- a/code/OpenGEXExporter.h +++ b/code/OpenGEXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2014, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/assimp/types.h" -#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER +#ifndef ASSIMP_BUILD_NO_OPENGEX_EXPORTER namespace Assimp { @@ -50,16 +50,17 @@ struct aiScene; namespace OpenGEX { - class OpenGEXExporter { - public: - OpenGEXExporter(); - ~OpenGEXExporter(); - bool exportScene( const char *filename, const aiScene* pScene ); - }; -} // Namespace openGEX +class OpenGEXExporter { +public: + OpenGEXExporter(); + ~OpenGEXExporter(); + bool exportScene( const char *filename, const aiScene* pScene ); +}; + +} // Namespace OpenGEX } // Namespace Assimp -#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER +#endif // ASSIMP_BUILD_NO_OPENGEX_EXPORTER #endif // AI_OPENGEX_EXPORTER_H diff --git a/code/OpenGEXImporter.cpp b/code/OpenGEXImporter.cpp index f260cc772..0a6d510fc 100644 --- a/code/OpenGEXImporter.cpp +++ b/code/OpenGEXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2014, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -183,7 +183,9 @@ OpenGEXImporter::VertexContainer::VertexContainer() , m_numNormals( 0 ) , m_normals(NULL) , m_numUVComps() -, m_textureCoords() { +, m_textureCoords() + { + // empty } //------------------------------------------------------------------------------------------------ @@ -217,11 +219,13 @@ OpenGEXImporter::OpenGEXImporter() , m_ctx( NULL ) , m_metrics() , m_currentNode( NULL ) +, m_currentVertices() , m_currentMesh( NULL ) , m_currentMaterial( NULL ) , m_tokenType( Grammar::NoneType ) , m_nodeStack() , m_unresolvedRefStack() { + // empty } //------------------------------------------------------------------------------------------------ @@ -420,7 +424,7 @@ static void getRefNames( DDLNode *node, std::vector &names ) { for( size_t i = 0; i < ref->m_numRefs; i++ ) { Name *currentName( ref->m_referencedName[ i ] ); if( NULL != currentName && NULL != currentName->m_id ) { - const std::string name( currentName->m_id->m_text.m_buffer ); + const std::string name( currentName->m_id->m_buffer ); if( !name.empty() ) { names.push_back( name ); } @@ -538,7 +542,7 @@ static void propId2StdString( Property *prop, std::string &name, std::string &ke } if( NULL != prop->m_key ) { - name = prop->m_key->m_text.m_buffer; + name = prop->m_key->m_buffer; if( Value::ddl_string == prop->m_value->m_type ) { key = prop->m_value->getString(); } @@ -661,6 +665,7 @@ void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene } const size_t numItems( countDataArrayListItems( vaList ) ); + if( Position == attribType ) { m_currentVertices.m_numVerts = numItems; m_currentVertices.m_vertices = new aiVector3D[ numItems ]; @@ -710,7 +715,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene * current.mIndices = new unsigned int[ current.mNumIndices ]; Value *next( vaList->m_dataList ); for( size_t indices = 0; indices < current.mNumIndices; indices++ ) { - const int idx = next->getInt32(); + const int idx( next->getUnsignedInt32() ); ai_assert( static_cast( idx ) <= m_currentVertices.m_numVerts ); aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] ); @@ -754,12 +759,16 @@ enum ColorType { }; //------------------------------------------------------------------------------------------------ -static ColorType getColorType( Identifier *id ) { - if( id->m_text == Grammar::DiffuseColorToken ) { +static ColorType getColorType( Text *id ) { + if ( NULL == id ) { + return NoneColor; + } + + if( *id == Grammar::DiffuseColorToken ) { return DiffuseColor; - } else if( id->m_text == Grammar::SpecularColorToken ) { + } else if( *id == Grammar::SpecularColorToken ) { return SpecularColor; - } else if( id->m_text == Grammar::EmissionColorToken ) { + } else if( *id == Grammar::EmissionColorToken ) { return EmissionColor; } diff --git a/code/OpenGEXImporter.h b/code/OpenGEXImporter.h index d187c4ac4..bcb87b7e0 100644 --- a/code/OpenGEXImporter.h +++ b/code/OpenGEXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2014, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OpenGEXStructs.h b/code/OpenGEXStructs.h index 62520df20..837597975 100644 --- a/code/OpenGEXStructs.h +++ b/code/OpenGEXStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2014, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OptimizeGraph.cpp b/code/OptimizeGraph.cpp index 2223bfbca..ec37bd447 100644 --- a/code/OptimizeGraph.cpp +++ b/code/OptimizeGraph.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -177,7 +177,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list& no ++it; } if (join_master && !join.empty()) { - join_master->mName.length = sprintf(join_master->mName.data,"$MergedNode_%i",count_merged++); + join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++); unsigned int out_meshes = 0; for (std::list::iterator it = join.begin(); it != join.end(); ++it) { @@ -335,7 +335,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) if ( nodes_in != nodes_out) { char buf[512]; - sprintf(buf,"OptimizeGraphProcess finished; Input nodes: %u, Output nodes: %u",nodes_in,nodes_out); + ::ai_snprintf(buf,512,"OptimizeGraphProcess finished; Input nodes: %u, Output nodes: %u",nodes_in,nodes_out); DefaultLogger::get()->info(buf); } else DefaultLogger::get()->debug("OptimizeGraphProcess finished"); diff --git a/code/OptimizeGraph.h b/code/OptimizeGraph.h index a586b8795..7ac9b00e8 100644 --- a/code/OptimizeGraph.h +++ b/code/OptimizeGraph.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OptimizeMeshes.cpp b/code/OptimizeMeshes.cpp index ae596f9c5..8d830bb9b 100644 --- a/code/OptimizeMeshes.cpp +++ b/code/OptimizeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -150,7 +150,7 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene) if (output.size() != num_old) { char tmp[512]; - ::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %u, Output meshes: %u",num_old,pScene->mNumMeshes); + ::ai_snprintf(tmp,512,"OptimizeMeshesProcess finished. Input meshes: %u, Output meshes: %u",num_old,pScene->mNumMeshes); DefaultLogger::get()->info(tmp); } else { DefaultLogger::get()->debug( "OptimizeMeshesProcess finished" ); diff --git a/code/OptimizeMeshes.h b/code/OptimizeMeshes.h index 2409eb862..ac7801c0a 100644 --- a/code/OptimizeMeshes.h +++ b/code/OptimizeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ParsingUtils.h b/code/ParsingUtils.h index 124813884..07f2c1846 100644 --- a/code/ParsingUtils.h +++ b/code/ParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_PARSING_UTILS_H_INC #include "StringComparison.h" +#include "StringUtils.h" #include "../include/assimp/defs.h" namespace Assimp { diff --git a/code/PlyExporter.cpp b/code/PlyExporter.cpp index 0a23e4b75..607f332c2 100644 --- a/code/PlyExporter.cpp +++ b/code/PlyExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "qnan.h" -using namespace Assimp; +//using namespace Assimp; namespace Assimp { // ------------------------------------------------------------------------------------------------ @@ -86,8 +86,6 @@ void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* outfile->Write(exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()), 1); } -} // end of namespace Assimp - #define PLY_EXPORT_HAS_NORMALS 0x1 #define PLY_EXPORT_HAS_TANGENTS_BITANGENTS 0x2 #define PLY_EXPORT_HAS_TEXCOORDS 0x4 @@ -216,6 +214,11 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina } } +// ------------------------------------------------------------------------------------------------ +PlyExporter::~PlyExporter() { + // empty +} + // ------------------------------------------------------------------------------------------------ void PlyExporter::WriteMeshVerts(const aiMesh* m, unsigned int components) { @@ -367,4 +370,6 @@ void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset) WriteMeshIndicesBinary_Generic(m, offset, mOutput); } -#endif +} // end of namespace Assimp + +#endif // !defined(ASSIMP_BUILD_NO_EXPORT) && !defined(ASSIMP_BUILD_NO_PLY_EXPORTER) diff --git a/code/PlyExporter.h b/code/PlyExporter.h index 254a08284..be4fa466f 100644 --- a/code/PlyExporter.h +++ b/code/PlyExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -59,30 +59,30 @@ namespace Assimp class PlyExporter { public: - /// Constructor for a specific scene to export + /// The class constructor for a specific scene to export PlyExporter(const char* filename, const aiScene* pScene, bool binary = false); + /// The class destructor, empty. + ~PlyExporter(); public: - - /// public stringstreams to write all output into + /// public string-streams to write all output into: std::ostringstream mOutput; private: - void WriteMeshVerts(const aiMesh* m, unsigned int components); void WriteMeshIndices(const aiMesh* m, unsigned int ofs); - void WriteMeshVertsBinary(const aiMesh* m, unsigned int components); void WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset); private: + const std::string filename; // tHE FILENAME + const std::string endl; // obviously, this endl() doesn't flush() the stream - const std::string filename; - - // obviously, this endl() doesn't flush() the stream - const std::string endl; +private: + PlyExporter( const PlyExporter & ); + PlyExporter &operator = ( const PlyExporter & ); }; -} +} // Namespace Assimp -#endif +#endif // AI_PLYEXPORTER_H_INC diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index f86ddcead..1378d1ebb 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -312,6 +312,7 @@ void PLYImporter::ConvertMeshes(std::vector* avFaces, p_pcOut->mNumVertices = iNum; if( 0 == iNum ) { // nothing to do delete[] aiSplit; // cleanup + delete p_pcOut; return; } p_pcOut->mVertices = new aiVector3D[iNum]; diff --git a/code/PlyLoader.h b/code/PlyLoader.h index 91be5c990..d83e70be3 100644 --- a/code/PlyLoader.h +++ b/code/PlyLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 8d6ce0698..df7d6883b 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/PlyParser.h b/code/PlyParser.h index c048db3cf..2753c1004 100644 --- a/code/PlyParser.h +++ b/code/PlyParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PolyTools.h b/code/PolyTools.h index 3a390585c..d2539d65d 100644 --- a/code/PolyTools.h +++ b/code/PolyTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PostStepRegistry.cpp b/code/PostStepRegistry.cpp index c12310c30..31518c132 100644 --- a/code/PostStepRegistry.cpp +++ b/code/PostStepRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 95e0a790c..d37bfd599 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -644,7 +644,7 @@ void PretransformVertices::Execute( aiScene* pScene) { aiNode* pcNode = *nodes = new aiNode(); pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%u",i); + pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"mesh_%u",i); // setup mesh indices pcNode->mNumMeshes = 1; @@ -656,7 +656,7 @@ void PretransformVertices::Execute( aiScene* pScene) { aiNode* pcNode = *nodes = new aiNode(); pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%u",i); + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i); pScene->mLights[i]->mName = pcNode->mName; } // generate camera nodes @@ -664,7 +664,7 @@ void PretransformVertices::Execute( aiScene* pScene) { aiNode* pcNode = *nodes = new aiNode(); pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%u",i); + pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i); pScene->mCameras[i]->mName = pcNode->mName; } } @@ -707,15 +707,15 @@ void PretransformVertices::Execute( aiScene* pScene) DefaultLogger::get()->debug("PretransformVerticesProcess finished"); - sprintf(buffer,"Removed %u nodes and %u animation channels (%u output nodes)", + ::ai_snprintf(buffer,4096,"Removed %u nodes and %u animation channels (%u output nodes)", iOldNodes,iOldAnimationChannels,CountNodes(pScene->mRootNode)); DefaultLogger::get()->info(buffer); - sprintf(buffer,"Kept %u lights and %u cameras", + ai_snprintf(buffer, 4096,"Kept %u lights and %u cameras", pScene->mNumLights,pScene->mNumCameras); DefaultLogger::get()->info(buffer); - sprintf(buffer,"Moved %u meshes to WCS (number of output meshes: %u)", + ai_snprintf(buffer, 4096,"Moved %u meshes to WCS (number of output meshes: %u)", iOldMeshes,pScene->mNumMeshes); DefaultLogger::get()->info(buffer); } diff --git a/code/PretransformVertices.h b/code/PretransformVertices.h index 2b358002a..307c9017e 100644 --- a/code/PretransformVertices.h +++ b/code/PretransformVertices.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ProcessHelper.cpp b/code/ProcessHelper.cpp index cb38d96ef..e18d54c30 100644 --- a/code/ProcessHelper.cpp +++ b/code/ProcessHelper.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -95,12 +95,16 @@ void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& } // ------------------------------------------------------------------------------- -void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) -{ - if (scene->mNumMeshes == 0) return; +void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) { + if ( NULL == scene ) { + return; + } + + if ( 0 == scene->mNumMeshes ) { + return; + } FindMeshCenter(scene->mMeshes[0], out, min, max); - for (unsigned int i = 1; i < scene->mNumMeshes; ++i) - { + for (unsigned int i = 1; i < scene->mNumMeshes; ++i) { aiVector3D tout, tmin, tmax; FindMeshCenter(scene->mMeshes[i], tout, tmin, tmax); if (min[0] > tmin[0]) min[0] = tmin[0]; @@ -151,6 +155,8 @@ float ComputePositionEpsilon(const aiMesh* pMesh) // ------------------------------------------------------------------------------- float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num) { + ai_assert( NULL != pMeshes ); + const float epsilon = 1e-4f; // calculate the position bounds so we have a reliable epsilon to check position differences against diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index c13c52562..2a7577610 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Profiler.h b/code/Profiler.h index 81935f2d8..c2b8b5009 100644 --- a/code/Profiler.h +++ b/code/Profiler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPFileImporter.cpp b/code/Q3BSPFileImporter.cpp index c27b0c63c..2526aeb26 100644 --- a/code/Q3BSPFileImporter.cpp +++ b/code/Q3BSPFileImporter.cpp @@ -325,7 +325,7 @@ void Q3BSPFileImporter::CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* p matIdx++; } - pScene->mNumMeshes = MeshArray.size(); + pScene->mNumMeshes = static_cast( MeshArray.size() ); if ( pScene->mNumMeshes > 0 ) { pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; diff --git a/code/Q3BSPZipArchive.cpp b/code/Q3BSPZipArchive.cpp index cc21754b3..cdc6ea2c5 100644 --- a/code/Q3BSPZipArchive.cpp +++ b/code/Q3BSPZipArchive.cpp @@ -292,7 +292,7 @@ bool Q3BSPZipArchive::mapArchive() { // The file has EXACTLY the size of uncompressed_size. In C // you need to mark the last character with '\0', so add // another character - if(unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) { + if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) { std::pair::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size))); if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) { diff --git a/code/Q3BSPZipArchive.h b/code/Q3BSPZipArchive.h index 333db5960..3b9bc2b3f 100644 --- a/code/Q3BSPZipArchive.h +++ b/code/Q3BSPZipArchive.h @@ -90,7 +90,7 @@ class ZipFile : public IOStream { public: - ZipFile(size_t size); + explicit ZipFile(size_t size); ~ZipFile(); diff --git a/code/Q3DLoader.cpp b/code/Q3DLoader.cpp index f5ec60185..cb73c3fe4 100644 --- a/code/Q3DLoader.cpp +++ b/code/Q3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/Q3DLoader.h b/code/Q3DLoader.h index 02eb0a426..89f4279fa 100644 --- a/code/Q3DLoader.h +++ b/code/Q3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -103,7 +103,7 @@ private: struct Face { - Face(unsigned int s) + explicit Face(unsigned int s) : indices (s) , uvindices (s) , mat (0) diff --git a/code/RawLoader.cpp b/code/RawLoader.cpp index 1462ec562..0945fe19f 100644 --- a/code/RawLoader.cpp +++ b/code/RawLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/RawLoader.h b/code/RawLoader.h index 85d52c795..436966cd9 100644 --- a/code/RawLoader.h +++ b/code/RawLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -88,7 +88,7 @@ private: struct MeshInformation { - MeshInformation(const std::string& _name) + explicit MeshInformation(const std::string& _name) : name(_name) { vertices.reserve(100); @@ -103,7 +103,7 @@ private: struct GroupInformation { - GroupInformation(const std::string& _name) + explicit GroupInformation(const std::string& _name) : name(_name) { meshes.reserve(10); diff --git a/code/RemoveComments.cpp b/code/RemoveComments.cpp index 44615f439..8290d2217 100644 --- a/code/RemoveComments.cpp +++ b/code/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveComments.h b/code/RemoveComments.h index 87bb81b4e..55eab9943 100644 --- a/code/RemoveComments.h +++ b/code/RemoveComments.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index 290396f20..a3e61ae8d 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -55,7 +55,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() -{ +: configFixedMaterials() { // nothing to do here } @@ -126,16 +126,18 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) } } - // TODO: reimplement this algorithm to work in-place - unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials]; + // TODO: re-implement this algorithm to work in-place + unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; + for ( unsigned int i=0; imNumMaterials; i++ ) { + aiMappingTable[ i ] = 0; + } unsigned int iNewNum = 0; // Iterate through all materials and calculate a hash for them // store all hashes in a list and so a quick search whether // we do already have a specific hash. This allows us to // determine which materials are identical. - uint32_t* aiHashes; - aiHashes = new uint32_t[pScene->mNumMaterials]; + uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { // No mesh is referencing this material, remove it. @@ -177,18 +179,18 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) // generate new names for all modified materials const unsigned int idx = aiMappingTable[p]; - if (ppcMaterials[idx]) - { + if (ppcMaterials[idx]) { aiString sz; - sz.length = ::sprintf(sz.data,"JoinedMaterial_#%u",p); + sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p); ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME); - } - else + } else { ppcMaterials[idx] = pScene->mMaterials[p]; + } } // update all material indices for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { aiMesh* mesh = pScene->mMeshes[p]; + ai_assert( NULL!=mesh ); mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; } // delete the old material list @@ -207,7 +209,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) else { char szBuffer[128]; // should be sufficiently large - ::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. Removed %u redundant and %u unused materials.", + ::ai_snprintf(szBuffer,128,"RemoveRedundantMatsProcess finished. Removed %u redundant and %u unused materials.", redundantRemoved,unreferencedRemoved); DefaultLogger::get()->info(szBuffer); } diff --git a/code/RemoveRedundantMaterials.h b/code/RemoveRedundantMaterials.h index 81c9da345..fe9f564d0 100644 --- a/code/RemoveRedundantMaterials.h +++ b/code/RemoveRedundantMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveVCProcess.cpp b/code/RemoveVCProcess.cpp index bb9cd1b1c..17ad5ff33 100644 --- a/code/RemoveVCProcess.cpp +++ b/code/RemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -283,7 +283,7 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh) if (!pMesh->mTextureCoords[i])break; if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b) { - delete pMesh->mTextureCoords[i]; + delete [] pMesh->mTextureCoords[i]; pMesh->mTextureCoords[i] = NULL; ret = true; diff --git a/code/RemoveVCProcess.h b/code/RemoveVCProcess.h index f8a0a806c..2a434e9ab 100644 --- a/code/RemoveVCProcess.h +++ b/code/RemoveVCProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SGSpatialSort.cpp b/code/SGSpatialSort.cpp index 6a156f915..84061888e 100644 --- a/code/SGSpatialSort.cpp +++ b/code/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/SGSpatialSort.h b/code/SGSpatialSort.h index e60ee59d2..360037067 100644 --- a/code/SGSpatialSort.h +++ b/code/SGSpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -66,7 +66,7 @@ public: /** Construction from a given face array, handling smoothing groups * properly */ - SGSpatialSort(const std::vector& vPositions); + explicit SGSpatialSort(const std::vector& vPositions); // ------------------------------------------------------------------- /** Add a vertex to the spatial sort diff --git a/code/SIBImporter.cpp b/code/SIBImporter.cpp new file mode 100644 index 000000000..62db27f36 --- /dev/null +++ b/code/SIBImporter.cpp @@ -0,0 +1,924 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +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 SIBImporter.cpp + * @brief Implementation of the SIB importer class. + * + * The Nevercenter Silo SIB format is undocumented. + * All details here have been reverse engineered from + * studying the binary files output by Silo. + * + * Nevertheless, this implementation is reasonably complete. + */ + + +#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER + +// internal headers +#include "SIBImporter.h" +#include "ByteSwapper.h" +#include "StreamReader.h" +#include "TinyFormatter.h" +#include "../contrib/ConvertUTF/ConvertUTF.h" +#include "../include/assimp/IOSystem.hpp" +#include "../include/assimp/DefaultLogger.hpp" +#include "../include/assimp/scene.h" + + +using namespace Assimp; + +static const aiImporterDesc desc = { + "Silo SIB Importer", + "Richard Mitton (http://www.codersnotes.com/about)", + "", + "Does not apply subdivision.", + aiImporterFlags_SupportBinaryFlavour, + 0, 0, + 0, 0, + "sib" +}; + +struct SIBChunk +{ + uint32_t Tag; + uint32_t Size; +} PACK_STRUCT; + +enum { POS, NRM, UV, N }; + +typedef std::pair SIBPair; +static SIBPair makePair(uint32_t a, uint32_t b) { return (a pos, nrm, uv; + std::vector idx; + std::vector faceStart; + std::vector mtls; + std::vector edges; + std::map edgeMap; +}; + +struct SIBObject +{ + aiString name; + aiMatrix4x4 axis; + size_t meshIdx, meshCount; +}; + +struct SIB +{ + std::vector mtls; + std::vector meshes; + std::vector lights; + std::vector objs, insts; +}; + +// ------------------------------------------------------------------------------------------------ +static SIBEdge& GetEdge(SIBMesh* mesh, uint32_t posA, uint32_t posB) +{ + SIBPair pair = (posA < posB) ? SIBPair(posA, posB) : SIBPair(posB, posA); + std::map::iterator it = mesh->edgeMap.find(pair); + if (it != mesh->edgeMap.end()) + return mesh->edges[it->second]; + + SIBEdge edge; + edge.creased = false; + edge.faceA = edge.faceB = 0xffffffff; + mesh->edgeMap[pair] = mesh->edges.size(); + mesh->edges.push_back(edge); + return mesh->edges.back(); +} + +// ------------------------------------------------------------------------------------------------ +// Helpers for reading chunked data. + +#define TAG(A,B,C,D) ((A << 24) | (B << 16) | (C << 8) | D) + +static SIBChunk ReadChunk(StreamReaderLE* stream) +{ + SIBChunk chunk; + chunk.Tag = stream->GetU4(); + chunk.Size = stream->GetU4(); + if (chunk.Size > stream->GetRemainingSizeToLimit()) + DefaultLogger::get()->error("SIB: Chunk overflow"); + ByteSwap::Swap4(&chunk.Tag); + return chunk; +} + +static aiColor3D ReadColor(StreamReaderLE* stream) +{ + float r = stream->GetF4(); + float g = stream->GetF4(); + float b = stream->GetF4(); + stream->GetU4(); // Colors have an unused(?) 4th component. + return aiColor3D(r, g, b); +} + +static void UnknownChunk(StreamReaderLE* stream, const SIBChunk& chunk) +{ + char temp[5] = { + static_cast(( chunk.Tag>>24 ) & 0xff), + static_cast(( chunk.Tag>>16 ) & 0xff), + static_cast(( chunk.Tag>>8 ) & 0xff), + static_cast(chunk.Tag & 0xff), '\0' + }; + + DefaultLogger::get()->warn((Formatter::format(), "SIB: Skipping unknown '",temp,"' chunk.")); +} + +// Reads a UTF-16LE string and returns it at UTF-8. +static aiString ReadString(StreamReaderLE* stream, uint32_t numWChars) +{ + // Allocate buffers (max expansion is 1 byte -> 4 bytes for UTF-8) + UTF16* temp = new UTF16[numWChars]; + UTF8* str = new UTF8[numWChars * 4 + 1]; + for (uint32_t n=0;nGetU2(); + + // Convert it and NUL-terminate. + const UTF16 *start = temp, *end = temp + numWChars; + UTF8 *dest = str, *limit = str + numWChars*4; + ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion); + *dest = '\0'; + + // Return the final string. + aiString result = aiString((const char *)str); + delete[] str; + delete[] temp; + return result; +} + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +SIBImporter::SIBImporter() +{} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +SIBImporter::~SIBImporter() +{} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the class can handle the format of the given file. +bool SIBImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const +{ + return SimpleExtensionCheck(pFile, "sib"); +} + +// ------------------------------------------------------------------------------------------------ +const aiImporterDesc* SIBImporter::GetInfo () const +{ + return &desc; +} + +// ------------------------------------------------------------------------------------------------ +static void ReadVerts(SIBMesh* mesh, StreamReaderLE* stream, uint32_t count) +{ + mesh->pos.resize(count); + + for (uint32_t n=0;npos[n].x = stream->GetF4(); + mesh->pos[n].y = stream->GetF4(); + mesh->pos[n].z = stream->GetF4(); + } +} + +// ------------------------------------------------------------------------------------------------ +static void ReadFaces(SIBMesh* mesh, StreamReaderLE* stream) +{ + uint32_t ptIdx = 0; + while (stream->GetRemainingSizeToLimit() > 0) + { + uint32_t numPoints = stream->GetU4(); + + // Store room for the N index channels, plus the point count. + size_t pos = mesh->idx.size() + 1; + mesh->idx.resize(pos + numPoints*N); + mesh->idx[pos-1] = numPoints; + uint32_t *idx = &mesh->idx[pos]; + + mesh->faceStart.push_back(pos-1); + mesh->mtls.push_back(0); + + // Read all the position data. + // UV/normals will be supplied later. + // Positions are supplied indexed already, so we preserve that + // mapping. UVs are supplied uniquely, so we allocate unique indices. + for (uint32_t n=0;nGetU4(); + if (p >= mesh->pos.size()) + throw DeadlyImportError("Vertex index is out of range."); + idx[POS] = p; + idx[NRM] = ptIdx; + idx[UV] = ptIdx; + } + } + + // Allocate data channels for normals/UVs. + mesh->nrm.resize(ptIdx, aiVector3D(0,0,0)); + mesh->uv.resize(ptIdx, aiVector3D(0,0,0)); + + mesh->numPts = ptIdx; +} + +// ------------------------------------------------------------------------------------------------ +static void ReadUVs(SIBMesh* mesh, StreamReaderLE* stream) +{ + while (stream->GetRemainingSizeToLimit() > 0) + { + uint32_t faceIdx = stream->GetU4(); + uint32_t numPoints = stream->GetU4(); + + if (faceIdx >= mesh->faceStart.size()) + throw DeadlyImportError("Invalid face index."); + + uint32_t pos = mesh->faceStart[faceIdx]; + uint32_t *idx = &mesh->idx[pos + 1]; + + for (uint32_t n=0;nuv[id].x = stream->GetF4(); + mesh->uv[id].y = stream->GetF4(); + } + } +} + +// ------------------------------------------------------------------------------------------------ +static void ReadMtls(SIBMesh* mesh, StreamReaderLE* stream) +{ + // Material assignments are stored run-length encoded. + // Also, we add 1 to each material so that we can use mtl #0 + // as the default material. + uint32_t prevFace = stream->GetU4(); + uint32_t prevMtl = stream->GetU4() + 1; + while (stream->GetRemainingSizeToLimit() > 0) + { + uint32_t face = stream->GetU4(); + uint32_t mtl = stream->GetU4() + 1; + while (prevFace < face) + { + if (prevFace >= mesh->mtls.size()) + throw DeadlyImportError("Invalid face index."); + mesh->mtls[prevFace++] = prevMtl; + } + + prevFace = face; + prevMtl = mtl; + } + + while (prevFace < mesh->mtls.size()) + mesh->mtls[prevFace++] = prevMtl; +} + +// ------------------------------------------------------------------------------------------------ +static void ReadAxis(aiMatrix4x4& axis, StreamReaderLE* stream) +{ + axis.a4 = stream->GetF4(); + axis.b4 = stream->GetF4(); + axis.c4 = stream->GetF4(); + axis.d4 = 1; + axis.a1 = stream->GetF4(); + axis.b1 = stream->GetF4(); + axis.c1 = stream->GetF4(); + axis.d1 = 0; + axis.a2 = stream->GetF4(); + axis.b2 = stream->GetF4(); + axis.c2 = stream->GetF4(); + axis.d2 = 0; + axis.a3 = stream->GetF4(); + axis.b3 = stream->GetF4(); + axis.c3 = stream->GetF4(); + axis.d3 = 0; +} + +// ------------------------------------------------------------------------------------------------ +static void ReadEdges(SIBMesh* mesh, StreamReaderLE* stream) +{ + while (stream->GetRemainingSizeToLimit() > 0) + { + uint32_t posA = stream->GetU4(); + uint32_t posB = stream->GetU4(); + GetEdge(mesh, posA, posB); + } +} + +// ------------------------------------------------------------------------------------------------ +static void ReadCreases(SIBMesh* mesh, StreamReaderLE* stream) +{ + while (stream->GetRemainingSizeToLimit() > 0) + { + uint32_t edge = stream->GetU4(); + if (edge >= mesh->edges.size()) + throw DeadlyImportError("SIB: Invalid edge index."); + mesh->edges[edge].creased = true; + } +} + +// ------------------------------------------------------------------------------------------------ +static void ConnectFaces(SIBMesh* mesh) +{ + // Find faces connected to each edge. + size_t numFaces = mesh->faceStart.size(); + for (size_t faceIdx=0;faceIdxidx[mesh->faceStart[faceIdx]]; + uint32_t numPoints = *idx++; + uint32_t prev = idx[(numPoints-1)*N+POS]; + + for (uint32_t i=0;i& faceNormals) +{ + // Creased edges complicate this. We need to find the start/end range of the + // ring of faces that touch this position. + // We do this in two passes. The first pass is to find the end of the range, + // the second is to work backwards to the start and calculate the final normal. + aiVector3D vtxNormal; + for (int pass=0;pass<2;pass++) + { + vtxNormal = aiVector3D(0, 0, 0); + uint32_t startFaceIdx = faceIdx; + uint32_t prevFaceIdx = faceIdx; + + // Process each connected face. + while (true) + { + // Accumulate the face normal. + vtxNormal += faceNormals[faceIdx]; + + uint32_t nextFaceIdx = 0xffffffff; + + // Move to the next edge sharing this position. + uint32_t* idx = &mesh->idx[mesh->faceStart[faceIdx]]; + uint32_t numPoints = *idx++; + uint32_t posA = idx[(numPoints-1)*N+POS]; + for (uint32_t n=0;n 0.000000001f) + vtxNormal /= len; + return vtxNormal; +} + +// ------------------------------------------------------------------------------------------------ +static void CalculateNormals(SIBMesh* mesh) +{ + size_t numFaces = mesh->faceStart.size(); + + // Calculate face normals. + std::vector faceNormals(numFaces); + for (size_t faceIdx=0;faceIdxidx[mesh->faceStart[faceIdx]]; + uint32_t numPoints = *idx++; + + aiVector3D faceNormal(0, 0, 0); + + uint32_t *prev = &idx[(numPoints-1)*N]; + + for (uint32_t i=0;ipos[prev[POS]] ^ mesh->pos[next[POS]]; + prev = next; + } + + faceNormals[faceIdx] = faceNormal; + } + + // Calculate vertex normals. + for (size_t faceIdx=0;faceIdxidx[mesh->faceStart[faceIdx]]; + uint32_t numPoints = *idx++; + + for (uint32_t i=0;inrm[nrm] = vtxNorm; + } + } +} + +// ------------------------------------------------------------------------------------------------ +struct TempMesh +{ + std::vector vtx; + std::vector nrm; + std::vector uv; + std::vector faces; +}; + +static void ReadShape(SIB* sib, StreamReaderLE* stream) +{ + SIBMesh smesh; + aiString name; + + while (stream->GetRemainingSizeToLimit() >= sizeof(SIBChunk)) + { + SIBChunk chunk = ReadChunk(stream); + unsigned oldLimit = stream->SetReadLimit(stream->GetCurrentPos() + chunk.Size); + + switch (chunk.Tag) + { + case TAG('M','I','R','P'): break; // mirror plane maybe? + case TAG('I','M','R','P'): break; // instance mirror? (not supported here yet) + case TAG('D','I','N','F'): break; // display info, not needed + case TAG('P','I','N','F'): break; // ? + case TAG('V','M','I','R'): break; // ? + case TAG('F','M','I','R'): break; // ? + case TAG('T','X','S','M'): break; // ? + case TAG('F','A','H','S'): break; // ? + case TAG('V','R','T','S'): ReadVerts(&smesh, stream, chunk.Size/12); break; + case TAG('F','A','C','S'): ReadFaces(&smesh, stream); break; + case TAG('F','T','V','S'): ReadUVs(&smesh, stream); break; + case TAG('S','N','A','M'): name = ReadString(stream, chunk.Size/2); break; + case TAG('F','A','M','A'): ReadMtls(&smesh, stream); break; + case TAG('A','X','I','S'): ReadAxis(smesh.axis, stream); break; + case TAG('E','D','G','S'): ReadEdges(&smesh, stream); break; + case TAG('E','C','R','S'): ReadCreases(&smesh, stream); break; + default: UnknownChunk(stream, chunk); break; + } + + stream->SetCurrentPos(stream->GetReadLimit()); + stream->SetReadLimit(oldLimit); + } + + assert(smesh.faceStart.size() == smesh.mtls.size()); // sanity check + + // Silo doesn't store any normals in the file - we need to compute + // them ourselves. We can't let AssImp handle it as AssImp doesn't + // know about our creased edges. + ConnectFaces(&smesh); + CalculateNormals(&smesh); + + // Construct the transforms. + aiMatrix4x4 worldToLocal = smesh.axis; + worldToLocal.Inverse(); + aiMatrix4x4 worldToLocalN = worldToLocal; + worldToLocalN.a4 = worldToLocalN.b4 = worldToLocalN.c4 = 0.0f; + worldToLocalN.Inverse().Transpose(); + + // Allocate final mesh data. + // We'll allocate one mesh for each material. (we'll strip unused ones after) + std::vector meshes(sib->mtls.size()); + + // Un-index the source data and apply to each vertex. + for (unsigned fi=0;fi= meshes.size()) + { + DefaultLogger::get()->error("SIB: Face material index is invalid."); + mtl = 0; + } + + TempMesh& dest = meshes[mtl]; + + aiFace face; + face.mNumIndices = *idx++; + face.mIndices = new unsigned[face.mNumIndices]; + for (unsigned pt=0;ptmeshes.size(); + + // Now that we know the size of everything, + // we can build the final one-material-per-mesh data. + for (size_t n=0;nmName = name; + mesh->mNumFaces = src.faces.size(); + mesh->mFaces = new aiFace[mesh->mNumFaces]; + mesh->mNumVertices = src.vtx.size(); + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; + mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; + mesh->mNumUVComponents[0] = 2; + mesh->mMaterialIndex = n; + + for (unsigned i=0;imNumVertices;i++) + { + mesh->mVertices[i] = src.vtx[i]; + mesh->mNormals[i] = src.nrm[i]; + mesh->mTextureCoords[0][i] = src.uv[i]; + } + for (unsigned i=0;imNumFaces;i++) + { + mesh->mFaces[i] = src.faces[i]; + } + + sib->meshes.push_back(mesh); + } + + obj.meshCount = sib->meshes.size() - obj.meshIdx; + sib->objs.push_back(obj); +} + +// ------------------------------------------------------------------------------------------------ +static void ReadMaterial(SIB* sib, StreamReaderLE* stream) +{ + aiColor3D diff = ReadColor(stream); + aiColor3D ambi = ReadColor(stream); + aiColor3D spec = ReadColor(stream); + aiColor3D emis = ReadColor(stream); + float shiny = (float)stream->GetU4(); + + uint32_t nameLen = stream->GetU4(); + aiString name = ReadString(stream, nameLen/2); + uint32_t texLen = stream->GetU4(); + aiString tex = ReadString(stream, texLen/2); + + aiMaterial* mtl = new aiMaterial(); + mtl->AddProperty(&diff, 1, AI_MATKEY_COLOR_DIFFUSE); + mtl->AddProperty(&ambi, 1, AI_MATKEY_COLOR_AMBIENT); + mtl->AddProperty(&spec, 1, AI_MATKEY_COLOR_SPECULAR); + mtl->AddProperty(&emis, 1, AI_MATKEY_COLOR_EMISSIVE); + mtl->AddProperty(&shiny, 1, AI_MATKEY_SHININESS); + mtl->AddProperty(&name, AI_MATKEY_NAME); + if (tex.length > 0) { + mtl->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(0)); + mtl->AddProperty(&tex, AI_MATKEY_TEXTURE_AMBIENT(0)); + } + + sib->mtls.push_back(mtl); +} + +// ------------------------------------------------------------------------------------------------ +static void ReadLightInfo(aiLight* light, StreamReaderLE* stream) +{ + uint32_t type = stream->GetU4(); + switch (type) { + case 0: light->mType = aiLightSource_POINT; break; + case 1: light->mType = aiLightSource_SPOT; break; + case 2: light->mType = aiLightSource_DIRECTIONAL; break; + default: light->mType = aiLightSource_UNDEFINED; break; + } + + light->mPosition.x = stream->GetF4(); + light->mPosition.y = stream->GetF4(); + light->mPosition.z = stream->GetF4(); + light->mDirection.x = stream->GetF4(); + light->mDirection.y = stream->GetF4(); + light->mDirection.z = stream->GetF4(); + light->mColorDiffuse = ReadColor(stream); + light->mColorAmbient = ReadColor(stream); + light->mColorSpecular = ReadColor(stream); + float spotExponent = stream->GetF4(); + float spotCutoff = stream->GetF4(); + light->mAttenuationConstant = stream->GetF4(); + light->mAttenuationLinear = stream->GetF4(); + light->mAttenuationQuadratic = stream->GetF4(); + + // Silo uses the OpenGL default lighting model for it's + // spot cutoff/exponent. AssImp unfortunately, does not. + // Let's try and approximate it by solving for the + // 99% and 1% percentiles. + // OpenGL: I = cos(angle)^E + // Solving: angle = acos(I^(1/E)) + float E = 1.0f / std::max(spotExponent, 0.00001f); + float inner = acosf(powf(0.99f, E)); + float outer = acosf(powf(0.01f, E)); + + // Apply the cutoff. + outer = std::min(outer, AI_DEG_TO_RAD(spotCutoff)); + + light->mAngleInnerCone = std::min(inner, outer); + light->mAngleOuterCone = outer; +} + +static void ReadLight(SIB* sib, StreamReaderLE* stream) +{ + aiLight* light = new aiLight(); + + while (stream->GetRemainingSizeToLimit() >= sizeof(SIBChunk)) + { + SIBChunk chunk = ReadChunk(stream); + unsigned oldLimit = stream->SetReadLimit(stream->GetCurrentPos() + chunk.Size); + + switch (chunk.Tag) + { + case TAG('L','N','F','O'): ReadLightInfo(light, stream); break; + case TAG('S','N','A','M'): light->mName = ReadString(stream, chunk.Size/2); break; + default: UnknownChunk(stream, chunk); break; + } + + stream->SetCurrentPos(stream->GetReadLimit()); + stream->SetReadLimit(oldLimit); + } + + sib->lights.push_back(light); +} + +// ------------------------------------------------------------------------------------------------ +static void ReadScale(aiMatrix4x4& axis, StreamReaderLE* stream) +{ + aiMatrix4x4 scale; + scale.a1 = stream->GetF4(); + scale.b1 = stream->GetF4(); + scale.c1 = stream->GetF4(); + scale.d1 = stream->GetF4(); + scale.a2 = stream->GetF4(); + scale.b2 = stream->GetF4(); + scale.c2 = stream->GetF4(); + scale.d2 = stream->GetF4(); + scale.a3 = stream->GetF4(); + scale.b3 = stream->GetF4(); + scale.c3 = stream->GetF4(); + scale.d3 = stream->GetF4(); + scale.a4 = stream->GetF4(); + scale.b4 = stream->GetF4(); + scale.c4 = stream->GetF4(); + scale.d4 = stream->GetF4(); + + axis = axis * scale; +} + +static void ReadInstance(SIB* sib, StreamReaderLE* stream) +{ + SIBObject inst; + uint32_t shapeIndex = 0; + + while (stream->GetRemainingSizeToLimit() >= sizeof(SIBChunk)) + { + SIBChunk chunk = ReadChunk(stream); + unsigned oldLimit = stream->SetReadLimit(stream->GetCurrentPos() + chunk.Size); + + switch (chunk.Tag) + { + case TAG('D','I','N','F'): break; // display info, not needed + case TAG('P','I','N','F'): break; // ? + case TAG('A','X','I','S'): ReadAxis(inst.axis, stream); break; + case TAG('I','N','S','I'): shapeIndex = stream->GetU4(); break; + case TAG('S','M','T','X'): ReadScale(inst.axis, stream); break; + case TAG('S','N','A','M'): inst.name = ReadString(stream, chunk.Size/2); break; + default: UnknownChunk(stream, chunk); break; + } + + stream->SetCurrentPos(stream->GetReadLimit()); + stream->SetReadLimit(oldLimit); + } + + if (shapeIndex >= sib->objs.size()) + throw DeadlyImportError("SIB: Invalid shape index."); + + const SIBObject& src = sib->objs[shapeIndex]; + inst.meshIdx = src.meshIdx; + inst.meshCount = src.meshCount; + sib->insts.push_back(inst); +} + +// ------------------------------------------------------------------------------------------------ +static void CheckVersion(StreamReaderLE* stream) +{ + uint32_t version = stream->GetU4(); + if (version != 1) + throw DeadlyImportError("SIB: Unsupported file version."); +} + +static void ReadScene(SIB* sib, StreamReaderLE* stream) +{ + // Parse each chunk in turn. + while (stream->GetRemainingSizeToLimit() >= sizeof(SIBChunk)) + { + SIBChunk chunk = ReadChunk(stream); + unsigned oldLimit = stream->SetReadLimit(stream->GetCurrentPos() + chunk.Size); + + switch (chunk.Tag) + { + case TAG('H','E','A','D'): CheckVersion(stream); break; + case TAG('S','H','A','P'): ReadShape(sib, stream); break; + case TAG('G','R','P','S'): break; // group assignment, we don't import this + case TAG('T','E','X','P'): break; // ? + case TAG('I','N','S','T'): ReadInstance(sib, stream); break; + case TAG('M','A','T','R'): ReadMaterial(sib, stream); break; + case TAG('L','G','H','T'): ReadLight(sib, stream); break; + default: UnknownChunk(stream, chunk); break; + } + + stream->SetCurrentPos(stream->GetReadLimit()); + stream->SetReadLimit(oldLimit); + } +} + +// ------------------------------------------------------------------------------------------------ +// Imports the given file into the given scene structure. +void SIBImporter::InternReadFile(const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) +{ + StreamReaderLE stream(pIOHandler->Open(pFile, "rb")); + + // We should have at least one chunk + if (stream.GetRemainingSize() < 16) + throw DeadlyImportError("SIB file is either empty or corrupt: " + pFile); + + SIB sib; + + // Default material. + aiMaterial* defmtl = new aiMaterial; + aiString defname = aiString(AI_DEFAULT_MATERIAL_NAME); + defmtl->AddProperty(&defname, AI_MATKEY_NAME); + sib.mtls.push_back(defmtl); + + // Read it all. + ReadScene(&sib, &stream); + + // Join the instances and objects together. + size_t firstInst = sib.objs.size(); + sib.objs.insert(sib.objs.end(), sib.insts.begin(), sib.insts.end()); + sib.insts.clear(); + + // Transfer to the aiScene. + pScene->mNumMaterials = sib.mtls.size(); + pScene->mNumMeshes = sib.meshes.size(); + pScene->mNumLights = sib.lights.size(); + pScene->mMaterials = pScene->mNumMaterials ? new aiMaterial*[pScene->mNumMaterials] : NULL; + pScene->mMeshes = pScene->mNumMeshes ? new aiMesh*[pScene->mNumMeshes] : NULL; + pScene->mLights = pScene->mNumLights ? new aiLight*[pScene->mNumLights] : NULL; + if (pScene->mNumMaterials) + memcpy(pScene->mMaterials, &sib.mtls[0], sizeof(aiMaterial*) * pScene->mNumMaterials); + if (pScene->mNumMeshes) + memcpy(pScene->mMeshes, &sib.meshes[0], sizeof(aiMesh*) * pScene->mNumMeshes); + if (pScene->mNumLights) + memcpy(pScene->mLights, &sib.lights[0], sizeof(aiLight*) * pScene->mNumLights); + + // Construct the root node. + size_t childIdx = 0; + aiNode *root = new aiNode(); + root->mName.Set(""); + root->mNumChildren = sib.objs.size() + sib.lights.size(); + root->mChildren = root->mNumChildren ? new aiNode*[root->mNumChildren] : NULL; + pScene->mRootNode = root; + + // Add nodes for each object. + for (size_t n=0;nmChildren[childIdx++] = node; + node->mName = obj.name; + node->mParent = root; + node->mTransformation = obj.axis; + + node->mNumMeshes = obj.meshCount; + node->mMeshes = node->mNumMeshes ? new unsigned[node->mNumMeshes] : NULL; + for (unsigned i=0;imNumMeshes;i++) + node->mMeshes[i] = obj.meshIdx + i; + + // Mark instanced objects as being so. + if (n >= firstInst) + { + node->mMetaData = new aiMetadata; + node->mMetaData->mNumProperties = 1; + node->mMetaData->mKeys = new aiString[1]; + node->mMetaData->mValues = new aiMetadataEntry[1]; + node->mMetaData->Set(0, "IsInstance", true); + } + } + + // Add nodes for each light. + // (no transformation as the light is already in world space) + for (size_t n=0;nmChildren[childIdx++] = node; + node->mName = light->mName; + node->mParent = root; + } +} + +#endif // !! ASSIMP_BUILD_NO_SIB_IMPORTER diff --git a/code/SIBImporter.h b/code/SIBImporter.h new file mode 100644 index 000000000..d31241f79 --- /dev/null +++ b/code/SIBImporter.h @@ -0,0 +1,119 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +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 SIBImporter.h + * @brief Declaration of the SIB importer class. + */ +#ifndef AI_SIBIMPORTER_H_INCLUDED +#define AI_SIBIMPORTER_H_INCLUDED + +#include "BaseImporter.h" +#include "../include/assimp/types.h" +#include + +namespace Assimp { + +// --------------------------------------------------------------------------- +/** Importer class for the Nevercenter Silo SIB scene format +*/ +class SIBImporter : public BaseImporter +{ +public: + SIBImporter(); + ~SIBImporter(); + + +public: + + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; + +protected: + + // ------------------------------------------------------------------- + /** Return importer meta information. + * See #BaseImporter::GetInfo for the details + */ + const aiImporterDesc* GetInfo () const; + + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); + +private: + + struct MeshInformation + { + explicit MeshInformation(const std::string& _name) + : name(_name) + { + vertices.reserve(100); + colors.reserve(100); + } + + std::string name; + + std::vector vertices; + std::vector colors; + }; + + struct GroupInformation + { + explicit GroupInformation(const std::string& _name) + : name(_name) + { + meshes.reserve(10); + } + + std::string name; + std::vector meshes; + }; +}; + +} // end of namespace Assimp + +#endif // AI_SIBIMPORTER_H_INCLUDED diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index d2ebbde96..2da7da019 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -216,7 +216,7 @@ void SMDImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS void SMDImporter::LogErrorNoThrow(const char* msg) { char szTemp[1024]; - sprintf(szTemp,"Line %u: %s",iLineNumber,msg); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,msg); DefaultLogger::get()->error(szTemp); } @@ -226,7 +226,7 @@ void SMDImporter::LogWarning(const char* msg) { char szTemp[1024]; ai_assert(strlen(msg) < 1000); - sprintf(szTemp,"Line %u: %s",iLineNumber,msg); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,msg); DefaultLogger::get()->warn(szTemp); } @@ -655,7 +655,7 @@ void SMDImporter::CreateOutputMaterials() pScene->mMaterials[iMat] = pcMat; aiString szName; - szName.length = (size_t)::sprintf(szName.data,"Texture_%u",iMat); + szName.length = (size_t)ai_snprintf(szName.data,MAXLEN,"Texture_%u",iMat); pcMat->AddProperty(&szName,AI_MATKEY_NAME); if (aszTextures[iMat].length()) diff --git a/code/SMDLoader.h b/code/SMDLoader.h index 6575a641e..14155674a 100644 --- a/code/SMDLoader.h +++ b/code/SMDLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFile.h b/code/STEPFile.h index ae7df67da..d688fc9fd 100644 --- a/code/STEPFile.h +++ b/code/STEPFile.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -863,6 +863,7 @@ namespace STEP { : reader(reader) , splitter(*reader,true,true) , evaluated_count() + , schema( NULL ) {} public: diff --git a/code/STEPFileEncoding.cpp b/code/STEPFileEncoding.cpp index ec29af76d..679ca2210 100644 --- a/code/STEPFileEncoding.cpp +++ b/code/STEPFileEncoding.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFileEncoding.h b/code/STEPFileEncoding.h index 243d69b93..3aec83056 100644 --- a/code/STEPFileEncoding.h +++ b/code/STEPFileEncoding.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFileReader.cpp b/code/STEPFileReader.cpp index 126ee2431..3b415ddb9 100644 --- a/code/STEPFileReader.cpp +++ b/code/STEPFileReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFileReader.h b/code/STEPFileReader.h index 56be4c5e2..69cfc898c 100644 --- a/code/STEPFileReader.h +++ b/code/STEPFileReader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLExporter.cpp b/code/STLExporter.cpp index 36362c9a1..fe2cf163c 100644 --- a/code/STLExporter.cpp +++ b/code/STLExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLExporter.h b/code/STLExporter.h index 45aacd7d9..44b12344f 100644 --- a/code/STLExporter.h +++ b/code/STLExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 96cded883..8c8dbfc2e 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/STLLoader.h b/code/STLLoader.h index b073a66b0..2d310f65b 100644 --- a/code/STLLoader.h +++ b/code/STLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index 8807abc5d..b56e2e601 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // ---------------------------------------------------------------------------- #include "SceneCombiner.h" +#include "StringUtils.h" #include "fast_atof.h" #include "Hash.h" #include "time.h" @@ -310,7 +311,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, // continue; //} - src[i].idlen = ::sprintf(src[i].id,"$%.6X$_",i); + src[i].idlen = ai_snprintf(src[i].id, 32, "$%.6X$_",i); if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { @@ -492,7 +493,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, // To offset or not to offset, this is the question if (n != (int)duplicates[n]) { - // Get full scenegraph copy + // Get full scene-graph copy Copy( &node, (*cur)->mRootNode ); OffsetNodeMeshIndices(node,offset[duplicates[n]]); @@ -1127,10 +1128,11 @@ void SceneCombiner::Copy (aiTexture** _dest, const aiTexture* src) } // ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy (aiAnimation** _dest, const aiAnimation* src) +void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) { - ai_assert(NULL != _dest && NULL != src); - + ai_assert( NULL != _dest ); + ai_assert( NULL != src ); + aiAnimation* dest = *_dest = new aiAnimation(); // get a flat copy diff --git a/code/SceneCombiner.h b/code/SceneCombiner.h index 3e6f0da41..fe73ad4f5 100644 --- a/code/SceneCombiner.h +++ b/code/SceneCombiner.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -166,7 +166,7 @@ struct SceneHelper id[0] = 0; } - SceneHelper (aiScene* _scene) + explicit SceneHelper (aiScene* _scene) : scene (_scene) , idlen (0) { diff --git a/code/ScenePreprocessor.cpp b/code/ScenePreprocessor.cpp index 46f584010..7f187ad90 100644 --- a/code/ScenePreprocessor.cpp +++ b/code/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ScenePreprocessor.h b/code/ScenePreprocessor.h index 922400949..1ef2d3e3b 100644 --- a/code/ScenePreprocessor.h +++ b/code/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ScenePrivate.h b/code/ScenePrivate.h index 286e4d829..055a7e15d 100644 --- a/code/ScenePrivate.h +++ b/code/ScenePrivate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SkeletonMeshBuilder.cpp b/code/SkeletonMeshBuilder.cpp index 860c77212..a3ef75b65 100644 --- a/code/SkeletonMeshBuilder.cpp +++ b/code/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -73,9 +73,11 @@ SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bK root->mMeshes[0] = 0; // create a dummy material for the mesh - pScene->mNumMaterials = 1; - pScene->mMaterials = new aiMaterial*[1]; - pScene->mMaterials[0] = CreateMaterial(); + if(pScene->mNumMaterials==0){ + pScene->mNumMaterials = 1; + pScene->mMaterials = new aiMaterial*[1]; + pScene->mMaterials[0] = CreateMaterial(); + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/SkeletonMeshBuilder.h b/code/SkeletonMeshBuilder.h index b1b1b531c..fe9651088 100644 --- a/code/SkeletonMeshBuilder.h +++ b/code/SkeletonMeshBuilder.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SmoothingGroups.h b/code/SmoothingGroups.h index 2ce25a2e9..a9921e4e2 100644 --- a/code/SmoothingGroups.h +++ b/code/SmoothingGroups.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SmoothingGroups.inl b/code/SmoothingGroups.inl index 4f072ad1a..42c500070 100644 --- a/code/SmoothingGroups.inl +++ b/code/SmoothingGroups.inl @@ -119,7 +119,7 @@ void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups& sMesh) { vNormals += sMesh.mNormals[(*a)]; } - vNormals.Normalize(); + vNormals.NormalizeSafe(); // write back into all affected normals for (std::vector::const_iterator diff --git a/code/SortByPTypeProcess.cpp b/code/SortByPTypeProcess.cpp index 6c1378fa5..74867184a 100644 --- a/code/SortByPTypeProcess.cpp +++ b/code/SortByPTypeProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -397,7 +397,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene) if (!DefaultLogger::isNullLogger()) { char buffer[1024]; - ::sprintf(buffer,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)", + ::ai_snprintf(buffer,1024,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)", aiNumMeshesPerPType[0], ((configRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""), aiNumMeshesPerPType[1], ((configRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""), aiNumMeshesPerPType[2], ((configRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""), diff --git a/code/SortByPTypeProcess.h b/code/SortByPTypeProcess.h index 4e8e691a2..c834bfa3f 100644 --- a/code/SortByPTypeProcess.h +++ b/code/SortByPTypeProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SpatialSort.cpp b/code/SpatialSort.cpp index ca81607dc..3420983f0 100644 --- a/code/SpatialSort.cpp +++ b/code/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -246,7 +246,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition, // The best way to overcome this is the unit in the last place (ULP). A precision of 2 ULPs // tells us that a float does not differ more than 2 bits from the "real" value. ULPs are of - // logarithmic precision - around 1, they are 1÷(2^24) and around 10000, they are 0.00125. + // logarithmic precision - around 1, they are 1�(2^24) and around 10000, they are 0.00125. // For standard C math, we can assume a precision of 0.5 ULPs according to IEEE 754. The // incoming vertex positions might have already been transformed, probably using rather diff --git a/code/SpatialSort.h b/code/SpatialSort.h index ff4e32045..e4fb4a0c3 100644 --- a/code/SpatialSort.h +++ b/code/SpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitByBoneCountProcess.cpp b/code/SplitByBoneCountProcess.cpp index f31d7b90e..41f16ab78 100644 --- a/code/SplitByBoneCountProcess.cpp +++ b/code/SplitByBoneCountProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitByBoneCountProcess.h b/code/SplitByBoneCountProcess.h index d35f9f38c..f4816952d 100644 --- a/code/SplitByBoneCountProcess.h +++ b/code/SplitByBoneCountProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitLargeMeshes.cpp b/code/SplitLargeMeshes.cpp index a915d45b8..00bdc2ee3 100644 --- a/code/SplitLargeMeshes.cpp +++ b/code/SplitLargeMeshes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -128,7 +128,7 @@ void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, } // now build the new list - delete pcNode->mMeshes; + delete[] pcNode->mMeshes; pcNode->mNumMeshes = (unsigned int)aiEntries.size(); pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; diff --git a/code/SplitLargeMeshes.h b/code/SplitLargeMeshes.h index dda1c1f4f..58575c9a7 100644 --- a/code/SplitLargeMeshes.h +++ b/code/SplitLargeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StandardShapes.cpp b/code/StandardShapes.cpp index 3cd4450b2..359b632bb 100644 --- a/code/StandardShapes.cpp +++ b/code/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StandardShapes.h b/code/StandardShapes.h index 0c077c5f2..211422c5d 100644 --- a/code/StandardShapes.h +++ b/code/StandardShapes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StdOStreamLogStream.h b/code/StdOStreamLogStream.h index 02bf508af..be1b2c640 100644 --- a/code/StdOStreamLogStream.h +++ b/code/StdOStreamLogStream.h @@ -16,7 +16,7 @@ public: /** @brief Construction from an existing std::ostream * @param _ostream Output stream to be used */ - StdOStreamLogStream(std::ostream& _ostream); + explicit StdOStreamLogStream(std::ostream& _ostream); /** @brief Destructor */ ~StdOStreamLogStream(); diff --git a/code/StepExporter.cpp b/code/StepExporter.cpp index b41858696..90391aeff 100644 --- a/code/StepExporter.cpp +++ b/code/StepExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -137,10 +137,12 @@ namespace { // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export -StepExporter::StepExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file, const ExportProperties* pProperties) : mProperties(pProperties), mIOSystem(pIOSystem), mFile(file), mPath(path), mScene(pScene), endstr(";\n") -{ - CollectTrafos(pScene->mRootNode, trafos); - CollectMeshes(pScene->mRootNode, meshes); +StepExporter::StepExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, + const std::string& file, const ExportProperties* pProperties): + mProperties(pProperties),mIOSystem(pIOSystem),mFile(file), mPath(path), + mScene(pScene), endstr(";\n") { + CollectTrafos(pScene->mRootNode, trafos); + CollectMeshes(pScene->mRootNode, meshes); // make sure that all formatting happens using the standard, C locale and not the user's current locale mOutput.imbue( std::locale("C") ); diff --git a/code/StepExporter.h b/code/StepExporter.h index 521f35b23..3d36635e1 100644 --- a/code/StepExporter.h +++ b/code/StepExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StreamReader.h b/code/StreamReader.h index 0698d99f9..c7acf0af8 100644 --- a/code/StreamReader.h +++ b/code/StreamReader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -253,24 +253,26 @@ public: * * @param limit Maximum number of bytes to be read from * the beginning of the file. Specifying UINT_MAX - * resets the limit to the original end of the stream. */ - void SetReadLimit(unsigned int _limit) { - + * resets the limit to the original end of the stream. + * Returns the previously set limit. */ + unsigned int SetReadLimit(unsigned int _limit) { + unsigned int prev = GetReadLimit(); if (UINT_MAX == _limit) { limit = end; - return; + return prev; } limit = buffer + _limit; if (limit > end) { throw DeadlyImportError("StreamReader: Invalid read limit"); } + return prev; } // --------------------------------------------------------------------- /** Get the current read limit in bytes. Reading over this limit * accidentially raises an exception. */ - int GetReadLimit() const { + unsigned int GetReadLimit() const { return (unsigned int)(limit - buffer); } diff --git a/code/StreamWriter.h b/code/StreamWriter.h index 6c847403f..f25736171 100644 --- a/code/StreamWriter.h +++ b/code/StreamWriter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/StringComparison.h b/code/StringComparison.h index 346230326..ea4f761f1 100644 --- a/code/StringComparison.h +++ b/code/StringComparison.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StringUtils.h b/code/StringUtils.h new file mode 100644 index 000000000..275bcbfb2 --- /dev/null +++ b/code/StringUtils.h @@ -0,0 +1,84 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 INCLUDED_AI_STRINGUTILS_H +#define INCLUDED_AI_STRINGUTILS_H + +#include +#include +#include + +/// @fn ai_snprintf +/// @brief The portable version of the function snprintf ( C99 standard ), which works on visual studio compilers 2013 and earlier. +/// @param outBuf The buffer to write in +/// @param size The buffer size +/// @param format The format string +/// @param ap The additional arguments. +/// @return The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned. +#if defined(_MSC_VER) && _MSC_VER < 1900 + + inline int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { + int count(-1); + if (0 != size) { + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + } + if (count == -1) { + count = _vscprintf(format, ap); + } + + return count; + } + + inline int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { + int count; + va_list ap; + + va_start(ap, format); + count = c99_ai_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; + } + +#else +# define ai_snprintf snprintf +#endif + +#endif // INCLUDED_AI_STRINGUTILS_H + diff --git a/code/Subdivision.cpp b/code/Subdivision.cpp index 1443f46eb..012c70047 100644 --- a/code/Subdivision.cpp +++ b/code/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -344,7 +344,7 @@ void CatmullClarkSubdivider::InternSubdivide ( // faces in the mesh. They occur at outer model boundaries in non-closed // shapes. char tmp[512]; - sprintf(tmp,"Catmull-Clark Subdivider: got %u bad edges touching only one face (totally %u edges). ", + ai_snprintf(tmp, 512, "Catmull-Clark Subdivider: got %u bad edges touching only one face (totally %u edges). ", bad_cnt,static_cast(edges.size())); DefaultLogger::get()->debug(tmp); diff --git a/code/Subdivision.h b/code/Subdivision.h index 461f08882..658640f55 100644 --- a/code/Subdivision.h +++ b/code/Subdivision.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TargetAnimation.cpp b/code/TargetAnimation.cpp index 4f2ff88ee..97c757fe9 100644 --- a/code/TargetAnimation.cpp +++ b/code/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TargetAnimation.h b/code/TargetAnimation.h index d2355a6a7..b177e359b 100644 --- a/code/TargetAnimation.h +++ b/code/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TerragenLoader.cpp b/code/TerragenLoader.cpp index a184341fb..4e711fc5e 100644 --- a/code/TerragenLoader.cpp +++ b/code/TerragenLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/TerragenLoader.h b/code/TerragenLoader.h index 13044b43a..c216a2186 100644 --- a/code/TerragenLoader.h +++ b/code/TerragenLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TextureTransform.cpp b/code/TextureTransform.cpp index a2779630d..9436c773a 100644 --- a/code/TextureTransform.cpp +++ b/code/TextureTransform.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,10 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "TextureTransform.h" +#include "StringUtils.h" using namespace Assimp; - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer TextureTransformStep::TextureTransformStep() : @@ -107,7 +107,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) { out -= rounded*(float)AI_MATH_PI; - sprintf(szTemp,"Texture coordinate rotation %f can be simplified to %f",info.mRotation,out); + ai_snprintf(szTemp, 512, "Texture coordinate rotation %f can be simplified to %f",info.mRotation,out); DefaultLogger::get()->info(szTemp); } @@ -131,7 +131,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) if (aiTextureMapMode_Wrap == info.mapU) { // Wrap - simple take the fraction of the field out = info.mTranslation.x-(float)rounded; - sprintf(szTemp,"[w] UV U offset %f can be simplified to %f",info.mTranslation.x,out); + ai_snprintf(szTemp, 512, "[w] UV U offset %f can be simplified to %f", info.mTranslation.x, out); } else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) { // Mirror @@ -139,11 +139,11 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) rounded--; out = info.mTranslation.x-(float)rounded; - sprintf(szTemp,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out); + ai_snprintf(szTemp,512,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out); } else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) { // Clamp - translations beyond 1,1 are senseless - sprintf(szTemp,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x); + ai_snprintf(szTemp,512,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x); out = 1.f; } @@ -164,7 +164,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) if (aiTextureMapMode_Wrap == info.mapV) { // Wrap - simple take the fraction of the field out = info.mTranslation.y-(float)rounded; - sprintf(szTemp,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out); + ::ai_snprintf(szTemp,512,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out); } else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) { // Mirror @@ -172,11 +172,11 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) rounded--; out = info.mTranslation.x-(float)rounded; - sprintf(szTemp,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out); + ::ai_snprintf(szTemp,512,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out); } else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) { // Clamp - translations beyond 1,1 are senseless - sprintf(szTemp,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y); + ::ai_snprintf(szTemp,512,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y); out = 1.f; } @@ -447,7 +447,7 @@ void TextureTransformStep::Execute( aiScene* pScene) if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) { if (!DefaultLogger::isNullLogger()) { - ::sprintf(buffer,"%u UV channels required but just %u available", + ::ai_snprintf(buffer,1024,"%u UV channels required but just %u available", static_cast(trafo.size()),AI_MAX_NUMBER_OF_TEXTURECOORDS); DefaultLogger::get()->error(buffer); @@ -475,7 +475,7 @@ void TextureTransformStep::Execute( aiScene* pScene) // Write to the log if (!DefaultLogger::isNullLogger()) { - sprintf(buffer,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s", + ::ai_snprintf(buffer,1024,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s", q,n, (*it).mTranslation.x, (*it).mTranslation.y, @@ -558,7 +558,7 @@ void TextureTransformStep::Execute( aiScene* pScene) if (!DefaultLogger::isNullLogger()) { if (transformedChannels) { - ::sprintf(buffer,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)", + ::ai_snprintf(buffer,1024,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)", outChannels,inChannels,transformedChannels); DefaultLogger::get()->info(buffer); diff --git a/code/TextureTransform.h b/code/TextureTransform.h index 420bda98e..e05899dde 100644 --- a/code/TextureTransform.h +++ b/code/TextureTransform.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TinyFormatter.h b/code/TinyFormatter.h index 84ecfb62d..7a5e7d21f 100644 --- a/code/TinyFormatter.h +++ b/code/TinyFormatter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -97,7 +97,7 @@ public: // being bound to const ref& function parameters. Copying streams is not permitted, though. // This workaround avoids this by manually specifying a copy ctor. #if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - basic_formatter(const basic_formatter& other) { + explicit basic_formatter(const basic_formatter& other) { underlying << (string)other; } #endif diff --git a/code/TriangulateProcess.cpp b/code/TriangulateProcess.cpp index 361309f0c..f418a5357 100644 --- a/code/TriangulateProcess.cpp +++ b/code/TriangulateProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -342,7 +342,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) for(;*loc != ' '; ++loc); *loc++ = '_'; } - *(loc+sprintf(loc,"%i",i)) = ' '; + *(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' '; } diff --git a/code/TriangulateProcess.h b/code/TriangulateProcess.h index 8db8e8c8e..97b5004e1 100644 --- a/code/TriangulateProcess.h +++ b/code/TriangulateProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/UnrealLoader.cpp b/code/UnrealLoader.cpp index c1795cda9..2ebff1dd4 100644 --- a/code/UnrealLoader.cpp +++ b/code/UnrealLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -377,7 +377,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, aiColor3D color(1.f,1.f,1.f); aiString s; - ::sprintf(s.data,"mat%u_tx%u_",i,materials[i].tex); + ::ai_snprintf( s.data, MAXLEN, "mat%u_tx%u_",i,materials[i].tex ); // set the two-sided flag if (materials[i].type == Unreal::MF_NORMAL_TS) { @@ -397,7 +397,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // a special name for the weapon attachment point if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) { - s.length = ::sprintf(s.data,"$WeaponTag$"); + s.length = ::ai_snprintf( s.data, MAXLEN, "$WeaponTag$" ); color = aiColor3D(0.f,0.f,0.f); } diff --git a/code/UnrealLoader.h b/code/UnrealLoader.h index e9b6c404a..93648ca82 100644 --- a/code/UnrealLoader.h +++ b/code/UnrealLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -87,7 +87,7 @@ struct TempMat { , numFaces (0) {} - TempMat(const Triangle& in) + explicit TempMat(const Triangle& in) : type ((Unreal::MeshFlags)in.mType) , tex (in.mTextureNum) , numFaces (0) diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index ba8e58fd2..bfb01276d 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/ValidateDataStructure.h b/code/ValidateDataStructure.h index 538f40c89..7472a2b1d 100644 --- a/code/ValidateDataStructure.h +++ b/code/ValidateDataStructure.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Version.cpp b/code/Version.cpp index c17069695..c61043567 100644 --- a/code/Version.cpp +++ b/code/Version.cpp @@ -6,7 +6,7 @@ #include "ScenePrivate.h" static const unsigned int MajorVersion = 3; -static const unsigned int MinorVersion = 1; +static const unsigned int MinorVersion = 2; // -------------------------------------------------------------------------------- // Legal information string - dont't remove this. diff --git a/code/Vertex.h b/code/Vertex.h index dc95e72e7..ad850455d 100644 --- a/code/Vertex.h +++ b/code/Vertex.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/VertexTriangleAdjacency.cpp b/code/VertexTriangleAdjacency.cpp index 7801e9cdd..c0cd209eb 100644 --- a/code/VertexTriangleAdjacency.cpp +++ b/code/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/VertexTriangleAdjacency.h b/code/VertexTriangleAdjacency.h index 4524caac2..18571590d 100644 --- a/code/VertexTriangleAdjacency.h +++ b/code/VertexTriangleAdjacency.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XFileExporter.cpp b/code/XFileExporter.cpp index 55cf95c5d..67a74150e 100644 --- a/code/XFileExporter.cpp +++ b/code/XFileExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -309,12 +309,12 @@ void XFileExporter::WriteNode( aiNode* pNode) WriteFrameTransform(m); - for (size_t i = 0; i < pNode->mNumMeshes; i++) + for (size_t i = 0; i < pNode->mNumMeshes; ++i) WriteMesh(mScene->mMeshes[pNode->mMeshes[i]]); // recursive call the Nodes for (size_t i = 0; i < pNode->mNumChildren; ++i) - WriteNode( mScene->mRootNode->mChildren[i]); + WriteNode(pNode->mChildren[i]); PopTag(); diff --git a/code/XFileExporter.h b/code/XFileExporter.h index a1b0518ea..3389ccd00 100644 --- a/code/XFileExporter.h +++ b/code/XFileExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XFileHelper.h b/code/XFileHelper.h index cb5d9abb0..b28c8ddfe 100644 --- a/code/XFileHelper.h +++ b/code/XFileHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -129,7 +129,7 @@ struct Mesh std::vector mBones; - Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; } + explicit Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; } }; /** Helper structure to represent a XFile frame */ @@ -142,7 +142,7 @@ struct Node std::vector mMeshes; Node() { mParent = NULL; } - Node( Node* pParent) { mParent = pParent; } + explicit Node( Node* pParent) { mParent = pParent; } ~Node() { for( unsigned int a = 0; a < mChildren.size(); a++) diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index 74e567c7c..b63ac4a1d 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/XFileImporter.h b/code/XFileImporter.h index c2dac3241..6066d19df 100644 --- a/code/XFileImporter.h +++ b/code/XFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XFileParser.cpp b/code/XFileParser.cpp index 2da71f02c..8ba03ac6a 100644 --- a/code/XFileParser.cpp +++ b/code/XFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/XFileParser.h b/code/XFileParser.h index e4308a6e2..995e5cfeb 100644 --- a/code/XFileParser.h +++ b/code/XFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -68,7 +68,7 @@ public: /** Constructor. Creates a data structure out of the XFile given in the memory block. * @param pBuffer Null-terminated memory buffer containing the XFile */ - XFileParser( const std::vector& pBuffer); + explicit XFileParser( const std::vector& pBuffer); /** Destructor. Destroys all imported data along with it */ ~XFileParser(); diff --git a/code/XGLLoader.cpp b/code/XGLLoader.cpp index 8de7f01c4..1d1a8d6c9 100644 --- a/code/XGLLoader.cpp +++ b/code/XGLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/code/XGLLoader.h b/code/XGLLoader.h index 51b9ef4e8..582c07429 100644 --- a/code/XGLLoader.h +++ b/code/XGLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XMLTools.h b/code/XMLTools.h index 6c7fa59c0..7339a2fc8 100644 --- a/code/XMLTools.h +++ b/code/XMLTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/glTFAsset.h b/code/glTFAsset.h new file mode 100644 index 000000000..c722a641b --- /dev/null +++ b/code/glTFAsset.h @@ -0,0 +1,945 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 glTFAsset.h + * Declares a glTF class to handle gltf/glb files + * + * glTF Extensions Support: + * KHR_binary_glTF: full + * KHR_materials_common: full + */ +#ifndef glTFAsset_H_INC +#define glTFAsset_H_INC + +#include +#include +#include +#include +#include + +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include + +#ifdef ASSIMP_API +# include "boost/shared_ptr.hpp" +# include "DefaultIOSystem.h" +# include "ByteSwapper.h" +#else +# include +# define AI_SWAP4(p) +# define ai_assert +#endif + + +#if _MSC_VER > 1500 || (defined __GNUC___) +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# else +# define gltf_unordered_map map +#endif + +#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# include +# if _MSC_VER > 1600 +# define gltf_unordered_map unordered_map +# else +# define gltf_unordered_map tr1::unordered_map +# endif +#endif + +namespace glTF +{ +#ifdef ASSIMP_API + using Assimp::IOStream; + using Assimp::IOSystem; + using boost::shared_ptr; +#else + using std::shared_ptr; + + typedef std::runtime_error DeadlyImportError; + typedef std::runtime_error DeadlyExportError; + + enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; + class IOSystem; + class IOStream + { + FILE* f; + public: + IOStream(FILE* file) : f(file) {} + ~IOStream() { fclose(f); f = 0; } + + size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } + size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } + int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } + size_t Tell() const { return ftell(f); } + + size_t FileSize() { + long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); + return size_t((Seek(p, aiOrigin_SET), len)); + } + }; +#endif + + using rapidjson::Value; + using rapidjson::Document; + + class Asset; + class AssetWriter; + + struct BufferView; // here due to cross-reference + struct Texture; + struct Light; + + + // Vec/matrix types, as raw float arrays + typedef float (vec3)[3]; + typedef float (vec4)[4]; + typedef float (mat4)[16]; + + + namespace Util + { + void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); + + size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); + + inline size_t DecodeBase64(const char* in, uint8_t*& out) + { + return DecodeBase64(in, strlen(in), out); + } + + struct DataURI + { + const char* mediaType; + const char* charset; + bool base64; + const char* data; + size_t dataLength; + }; + + //! Check if a uri is a data URI + inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); + } + + + //! Magic number for GLB files + #define AI_GLB_MAGIC_NUMBER "glTF" + + #ifdef ASSIMP_API + #include "./../include/assimp/Compiler/pushpack1.h" + #endif + + //! For the KHR_binary_glTF extension (binary .glb file) + //! 20-byte header (+ the JSON + a "body" data section) + struct GLB_Header + { + uint8_t magic[4]; //!< Magic number: "glTF" + uint32_t version; //!< Version number (always 1 as of the last update) + uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes + uint32_t sceneLength; //!< Length, in bytes, of the glTF scene + uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum) + } PACK_STRUCT; + + #ifdef ASSIMP_API + #include "./../include/assimp/Compiler/poppack1.h" + #endif + + + //! Values for the GLB_Header::sceneFormat field + enum SceneFormat + { + SceneFormat_JSON = 0 + }; + + //! Values for the mesh primitive modes + enum PrimitiveMode + { + PrimitiveMode_POINTS = 0, + PrimitiveMode_LINES = 1, + PrimitiveMode_LINE_LOOP = 2, + PrimitiveMode_LINE_STRIP = 3, + PrimitiveMode_TRIANGLES = 4, + PrimitiveMode_TRIANGLE_STRIP = 5, + PrimitiveMode_TRIANGLE_FAN = 6 + }; + + //! Values for the Accessor::componentType field + enum ComponentType + { + ComponentType_BYTE = 5120, + ComponentType_UNSIGNED_BYTE = 5121, + ComponentType_SHORT = 5122, + ComponentType_UNSIGNED_SHORT = 5123, + ComponentType_FLOAT = 5126 + }; + + inline size_t ComponentTypeSize(ComponentType t) + { + switch (t) { + case ComponentType_SHORT: + case ComponentType_UNSIGNED_SHORT: + return 2; + + case ComponentType_FLOAT: + return 4; + + //case Accessor::ComponentType_BYTE: + //case Accessor::ComponentType_UNSIGNED_BYTE: + default: + return 1; + } + } + + //! Values for the BufferView::target field + enum BufferViewTarget + { + BufferViewTarget_ARRAY_BUFFER = 34962, + BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 + }; + + //! Values for the Texture::format and Texture::internalFormat fields + enum TextureFormat + { + TextureFormat_ALPHA = 6406, + TextureFormat_RGB = 6407, + TextureFormat_RGBA = 6408, + TextureFormat_LUMINANCE = 6409, + TextureFormat_LUMINANCE_ALPHA = 6410 + }; + + //! Values for the Texture::target field + enum TextureTarget + { + TextureTarget_TEXTURE_2D = 3553 + }; + + //! Values for the Texture::type field + enum TextureType + { + TextureType_UNSIGNED_BYTE = 5121, + TextureType_UNSIGNED_SHORT_5_6_5 = 33635, + TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819, + TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820 + }; + + + //! Values for the Accessor::type field (helper class) + class AttribType + { + public: + enum Value + { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 }; + + private: + static const size_t NUM_VALUES = static_cast(MAT4)+1; + + struct Info + { const char* name; unsigned int numComponents; }; + + template struct data + { static const Info infos[NUM_VALUES]; }; + + public: + inline static Value FromString(const char* str) + { + for (size_t i = 0; i < NUM_VALUES; ++i) { + if (strcmp(data<0>::infos[i].name, str) == 0) { + return static_cast(i); + } + } + return SCALAR; + } + + inline static const char* ToString(Value type) + { + return data<0>::infos[static_cast(type)].name; + } + + inline static unsigned int GetNumComponents(Value type) + { + return data<0>::infos[static_cast(type)].numComponents; + } + }; + + // must match the order of the AttribTypeTraits::Value enum! + template const AttribType::Info + AttribType::data::infos[AttribType::NUM_VALUES] = { + { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } + }; + + + + //! A reference to one top-level object, which is valid + //! until the Asset instance is destroyed + template + class Ref + { + std::vector* vector; + int index; + + public: + Ref() : vector(0), index(0) {} + Ref(std::vector& vec, int idx) : vector(&vec), index(idx) {} + + inline size_t GetIndex() const + { return index; } + + operator bool() const + { return vector != 0; } + + T* operator->() + { return (*vector)[index]; } + + T& operator*() + { return *((*vector)[index]); } + }; + + //! Helper struct to represent values that might not be present + template + struct Nullable + { + T value; + bool isPresent; + + Nullable() : isPresent(false) {} + Nullable(T& val) : value(val), isPresent(true) {} + }; + + + //! Base classe for all glTF top-level objects + struct Object + { + std::string id; //!< The globally unique ID used to reference this object + std::string name; //!< The user-defined name of this object + + //! Objects marked as special are not exported (used to emulate the binary body buffer) + virtual bool IsSpecial() const + { return false; } + + virtual ~Object() {} + }; + + + + // + // Classes for each glTF top-level object type + // + + //! A typed view into a BufferView. A BufferView contains raw binary data. + //! An accessor provides a typed view into a BufferView or a subset of a BufferView + // !similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. + struct Accessor : public Object + { + Ref bufferView; //!< The ID of the bufferView. (required) + unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) + unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0) + ComponentType componentType; //!< The datatype of components in the attribute. (required) + unsigned int count; //!< The number of attributes referenced by this accessor. (required) + AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) + //std::vector max; //!< Maximum value of each component in this attribute. + //std::vector min; //!< Minimum value of each component in this attribute. + + unsigned int GetNumComponents(); + unsigned int GetBytesPerComponent(); + unsigned int GetElementSize(); + + inline uint8_t* GetPointer(); + + template + void ExtractData(T*& outData); + + void WriteData(size_t count, const void* src_buffer, size_t src_stride); + + //! Helper class to iterate the data + class Indexer + { + friend struct Accessor; + + Accessor& accessor; + uint8_t* data; + size_t elemSize, stride; + + Indexer(Accessor& acc); + + public: + + //! Accesses the i-th value as defined by the accessor + template + T GetValue(int i); + + //! Accesses the i-th value as defined by the accessor + inline unsigned int GetUInt(int i) + { + return GetValue(i); + } + }; + + inline Indexer GetIndexer() + { + return Indexer(*this); + } + + Accessor() {} + void Read(Value& obj, Asset& r); + }; + + + struct Animation : public Object + { + struct Channel + { + + }; + + struct Target + { + + }; + + struct Sampler + { + + }; + }; + + //! A buffer points to binary geometry, animation, or skins. + struct Buffer : public Object + { + public: + + enum Type + { + Type_arraybuffer, + Type_text + }; + + //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) + size_t byteLength; //!< The length of the buffer in bytes. (default: 0) + //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") + + Type type; + + private: + shared_ptr mData; //!< Pointer to the data + bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) + + public: + Buffer(); + + void Read(Value& obj, Asset& r); + + void LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); + + size_t AppendData(uint8_t* data, size_t length); + void Grow(size_t amount); + + uint8_t* GetPointer() + { return mData.get(); } + + void MarkAsSpecial() + { mIsSpecial = true; } + + bool IsSpecial() const + { return mIsSpecial; } + }; + + + //! A view into a buffer generally representing a subset of the buffer. + struct BufferView : public Object + { + Ref buffer; //! The ID of the buffer. (required) + size_t byteOffset; //! The offset into the buffer in bytes. (required) + size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + + BufferViewTarget target; //! The target that the WebGL buffer should be bound to. + + BufferView() {} + void Read(Value& obj, Asset& r); + }; + + + struct Camera : public Object + { + enum Type + { + Perspective, + Orthographic + }; + + Type type; + + union + { + struct { + float aspectRatio; //! bufferView; + + std::string mimeType; + + int width, height; + + private: + uint8_t* mData; + size_t mDataLength; + + public: + + Image(); + void Read(Value& obj, Asset& r); + + inline bool HasData() const + { return mDataLength > 0; } + + inline size_t GetDataLength() const + { return mDataLength; } + + inline const uint8_t* GetData() const + { return mData; } + + inline uint8_t* StealData(); + + inline void SetData(uint8_t* data, size_t length, Asset& r); + }; + + //! Holds a material property that can be a texture or a color + struct TexProperty + { + Ref texture; + vec4 color; + }; + + //! The material appearance of a primitive. + struct Material : public Object + { + //Ref source; //!< The ID of the technique. + //std::gltf_unordered_map values; //!< A dictionary object of parameter values. + + //! Techniques defined by KHR_materials_common + enum Technique + { + Technique_undefined = 0, + Technique_BLINN, + Technique_PHONG, + Technique_LAMBERT, + Technique_CONSTANT + }; + + TexProperty ambient; + TexProperty diffuse; + TexProperty specular; + TexProperty emission; + + bool doubleSided; + bool transparent; + float transparency; + float shininess; + + Technique technique; + + Material() { SetDefaults(); } + void Read(Value& obj, Asset& r); + void SetDefaults(); + }; + + //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. + struct Mesh : public Object + { + typedef std::vector< Ref > AccessorList; + + struct Primitive + { + PrimitiveMode mode; + + struct Attributes { + AccessorList position, normal, texcoord, color, joint, jointmatrix, weight; + } attributes; + + Ref indices; + + Ref material; + }; + + std::vector primitives; + + Mesh() {} + void Read(Value& obj, Asset& r); + }; + + struct Node : public Object + { + std::vector< Ref > children; + std::vector< Ref > meshes; + + Nullable matrix; + Nullable translation; + Nullable rotation; + Nullable scale; + + Ref camera; + Ref light; + + Node() {} + void Read(Value& obj, Asset& r); + }; + + struct Program : public Object + { + Program() {} + void Read(Value& obj, Asset& r); + }; + + + struct Sampler : public Object + { + Sampler() {} + void Read(Value& obj, Asset& r); + }; + + struct Scene : public Object + { + std::vector< Ref > nodes; + + Scene() {} + void Read(Value& obj, Asset& r); + }; + + struct Shader : public Object + { + Shader() {} + void Read(Value& obj, Asset& r); + }; + + struct Skin : public Object + { + Skin() {} + void Read(Value& obj, Asset& r); + }; + + struct Technique : public Object + { + struct Parameters + { + + }; + + struct States + { + + }; + + struct Functions + { + + }; + + Technique() {} + void Read(Value& obj, Asset& r); + }; + + //! A texture and its sampler. + struct Texture : public Object + { + //Ref source; //!< The ID of the sampler used by this texture. (required) + Ref source; //!< The ID of the image used by this texture. (required) + + //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) + //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA) + + //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D) + //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE) + + Texture() {} + void Read(Value& obj, Asset& r); + }; + + + //! A light (from KHR_materials_common extension) + struct Light : public Object + { + enum Type + { + Type_undefined, + Type_ambient, + Type_directional, + Type_point, + Type_spot + }; + + Type type; + + vec4 color; + float distance; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float falloffAngle; + float falloffExponent; + + Light() {} + void Read(Value& obj, Asset& r); + + void SetDefaults(); + }; + + //! Base class for LazyDict that acts as an interface + class LazyDictBase + { + public: + virtual ~LazyDictBase() {} + + virtual void AttachToDocument(Document& doc) = 0; + virtual void DetachFromDocument() = 0; + + virtual void WriteObjects(AssetWriter& writer) = 0; + }; + + //! (Stub class that is specialized in glTFAssetWriter.h) + template + struct LazyDictWriter + { + static void Write(T& d, AssetWriter& w) {} + }; + + //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID + //! It is the owner the loaded objects, so when it is destroyed it also deletes them + template + class LazyDict : public LazyDictBase + { + friend class Asset; + friend class AssetWriter; + + typedef typename std::gltf_unordered_map< std::string, size_t > Dict; + + std::vector mObjs; //! The read objects + Dict mObjsById; //! The read objects accesible by id + const char* mDictId; //! ID of the dictionary object + const char* mExtId; //! ID of the extension defining the dictionary + Value* mDict; //! JSON dictionary object + Asset& mAsset; //! The asset instance + + void AttachToDocument(Document& doc); + void DetachFromDocument(); + + void WriteObjects(AssetWriter& writer) + { LazyDictWriter< LazyDict >::Write(*this, writer); } + + Ref Add(T* obj); + + public: + LazyDict(Asset& asset, const char* dictId, const char* extId = 0); + ~LazyDict(); + + Ref Get(const char* id); + Ref Get(size_t i); + + Ref Create(const char* id); + Ref Create(const std::string& id) + { return Create(id.c_str()); } + + inline size_t Size() const + { return mObjs.size(); } + + inline T& operator[](size_t i) + { return *mObjs[i]; } + + }; + + + struct AssetMetadata + { + std::string copyright; //!< A copyright message suitable for display to credit the content creator. + std::string generator; //!< Tool that generated this glTF model.Useful for debugging. + bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false) + + struct { + std::string api; //!< Specifies the target rendering API (default: "WebGL") + std::string version; //!< Specifies the target rendering API (default: "1.0.3") + } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {}) + + int version; //!< The glTF format version (should be 1) + + void Read(Document& doc); + }; + + // + // glTF Asset class + // + + //! Root object for a glTF asset + class Asset + { + typedef std::gltf_unordered_map IdMap; + + template + friend class LazyDict; + + friend struct Buffer; // To access OpenFile + + friend class AssetWriter; + + private: + IOSystem* mIOSystem; + + std::string mCurrentAssetDir; + + size_t mSceneLength; + size_t mBodyOffset, mBodyLength; + + std::vector mDicts; + + IdMap mUsedIds; + + Ref mBodyBuffer; + + Asset(Asset&); + Asset& operator=(const Asset&); + + public: + + //! Keeps info about the enabled extensions + struct Extensions + { + bool KHR_binary_glTF; + bool KHR_materials_common; + + } extensionsUsed; + + AssetMetadata asset; + + + // Dictionaries for each type of object + + LazyDict accessors; + LazyDict animations; + LazyDict buffers; + LazyDict bufferViews; + LazyDict cameras; + LazyDict images; + LazyDict materials; + LazyDict meshes; + LazyDict nodes; + //LazyDict programs; + //LazyDict samplers; + LazyDict scenes; + //LazyDict shaders; + //LazyDict skins; + //LazyDict techniques; + LazyDict textures; + + LazyDict lights; // KHR_materials_common ext + + Ref scene; + + public: + Asset(IOSystem* io = 0) + : mIOSystem(io) + , accessors (*this, "accessors") + , animations (*this, "animations") + , buffers (*this, "buffers") + , bufferViews (*this, "bufferViews") + , cameras (*this, "cameras") + , images (*this, "images") + , materials (*this, "materials") + , meshes (*this, "meshes") + , nodes (*this, "nodes") + //, programs (*this, "programs") + //, samplers (*this, "samplers") + , scenes (*this, "scenes") + //, shaders (*this, "shaders") + //, skins (*this, "skins") + //, techniques (*this, "techniques") + , textures (*this, "textures") + , lights (*this, "lights", "KHR_materials_common") + { + memset(&extensionsUsed, 0, sizeof(extensionsUsed)); + memset(&asset, 0, sizeof(asset)); + } + + //! Main function + void Load(const std::string& file, bool isBinary = false); + + //! Enables the "KHR_binary_glTF" extension on the asset + void SetAsBinary(); + + //! Search for an available name, starting from the given strings + std::string FindUniqueID(const std::string& str, const char* suffix); + + Ref GetBodyBuffer() + { return mBodyBuffer; } + + private: + void ReadBinaryHeader(IOStream& stream); + + void ReadExtensionsUsed(Document& doc); + + + IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); + }; + +} + +// Include the implementation of the methods +#include "glTFAsset.inl" + +#endif diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl new file mode 100644 index 000000000..858788b43 --- /dev/null +++ b/code/glTFAsset.inl @@ -0,0 +1,1232 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "StringUtils.h" + +namespace glTF { + +namespace { + + // + // JSON Value reading helpers + // + + template + struct ReadHelper { static bool Read(Value& val, T& out) { + return val.IsInt() ? out = static_cast(val.GetInt()), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, bool& out) { + return val.IsBool() ? out = val.GetBool(), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, float& out) { + return val.IsNumber() ? out = static_cast(val.GetDouble()), true : false; + }}; + + template struct ReadHelper { static bool Read(Value& val, float (&out)[N]) { + if (!val.IsArray() || val.Size() != N) return false; + for (size_t i = 0; i < N; ++i) { + if (val[i].IsNumber()) + out[i] = static_cast(val[i].GetDouble()); + } + return true; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, const char*& out) { + return val.IsString() ? out = val.GetString(), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, std::string& out) { + return val.IsString() ? out = val.GetString(), true : false; + }}; + + template struct ReadHelper< Nullable > { static bool Read(Value& val, Nullable& out) { + return out.isPresent = ReadHelper::Read(val, out.value); + }}; + + template + inline static bool ReadValue(Value& val, T& out) + { + return ReadHelper::Read(val, out); + } + + template + inline static bool ReadMember(Value& obj, const char* id, T& out) + { + Value::MemberIterator it = obj.FindMember(id); + if (it != obj.MemberEnd()) { + return ReadHelper::Read(it->value, out); + } + return false; + } + + template + inline static T MemberOrDefault(Value& obj, const char* id, T defaultValue) + { + T out; + return ReadMember(obj, id, out) ? out : defaultValue; + } + + inline Value* FindMember(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd()) ? &it->value : 0; + } + + inline Value* FindString(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0; + } + + inline Value* FindArray(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0; + } + + inline Value* FindObject(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0; + } +} + +// +// LazyDict methods +// + +template +inline LazyDict::LazyDict(Asset& asset, const char* dictId, const char* extId) + : mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset) +{ + asset.mDicts.push_back(this); // register to the list of dictionaries +} + +template +inline LazyDict::~LazyDict() +{ + for (size_t i = 0; i < mObjs.size(); ++i) { + delete mObjs[i]; + } +} + + +template +inline void LazyDict::AttachToDocument(Document& doc) +{ + Value* container = 0; + + if (mExtId) { + if (Value* exts = FindObject(doc, "extensions")) { + container = FindObject(*exts, mExtId); + } + } + else { + container = &doc; + } + + if (container) { + mDict = FindObject(*container, mDictId); + } +} + +template +inline void LazyDict::DetachFromDocument() +{ + mDict = 0; +} + +template +Ref LazyDict::Get(size_t i) +{ + return Ref(mObjs, i); +} + +template +Ref LazyDict::Get(const char* id) +{ + typename Dict::iterator it = mObjsById.find(id); + if (it != mObjsById.end()) { // already created? + return Ref(mObjs, it->second); + } + + // read it from the JSON object + if (!mDict) { + return Ref(); // section is missing + } + + Value::MemberIterator obj = mDict->FindMember(id); + if (obj == mDict->MemberEnd()) { + throw DeadlyImportError("Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\""); + } + if (!obj->value.IsObject()) { + throw DeadlyImportError("Object with id \"" + std::string(id) + "\" is not a JSON object!"); + } + + // create an instance of the given type + T* inst = new T(); + inst->id = id; + ReadMember(obj->value, "name", inst->name); + inst->Read(obj->value, mAsset); + return Add(inst); +} + +template +Ref LazyDict::Add(T* obj) +{ + size_t idx = mObjs.size(); + mObjs.push_back(obj); + mObjsById[obj->id] = idx; + mAsset.mUsedIds[obj->id] = true; + return Ref(mObjs, idx); +} + +template +Ref LazyDict::Create(const char* id) +{ + Asset::IdMap::iterator it = mAsset.mUsedIds.find(id); + if (it != mAsset.mUsedIds.end()) { + throw DeadlyImportError("Two objects with the same ID exist!"); + } + T* inst = new T(); + inst->id = id; + return Add(inst); +} + + +// +// glTF dictionary objects methods +// + + +inline Buffer::Buffer() +: byteLength(0), type(Type_arraybuffer), mIsSpecial(false) +{ } + + +inline void Buffer::Read(Value& obj, Asset& r) +{ + size_t statedLength = MemberOrDefault(obj, "byteLength", 0); + byteLength = statedLength; + + Value* it = FindString(obj, "uri"); + if (!it) return; + + const char* uri = it->GetString(); + + Util::DataURI dataURI; + if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { + if (dataURI.base64) { + uint8_t* data = 0; + this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data); + this->mData.reset(data); + + if (statedLength > 0 && this->byteLength != statedLength) { + // error? + } + } + } + else { // Local file + if (byteLength > 0) { + IOStream* file = r.OpenFile(uri, "rb"); + if (file) { + LoadFromStream(*file, byteLength); + delete file; + } + } + } +} + +inline void Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset) +{ + byteLength = length ? length : stream.FileSize(); + + if (baseOffset) { + stream.Seek(baseOffset, aiOrigin_SET); + } + + mData.reset(new uint8_t[byteLength]); + + if (stream.Read(mData.get(), byteLength, 1) != 1) { + throw DeadlyImportError("Unable to load buffer from file!"); + } +} + +inline size_t Buffer::AppendData(uint8_t* data, size_t length) +{ + size_t offset = this->byteLength; + Grow(length); + memcpy(mData.get() + offset, data, length); + return offset; +} + +inline void Buffer::Grow(size_t amount) +{ + if (amount <= 0) return; + uint8_t* b = new uint8_t[byteLength + amount]; + if (mData) memcpy(b, mData.get(), byteLength); + mData.reset(b); + byteLength += amount; +} + + +inline void BufferView::Read(Value& obj, Asset& r) +{ + const char* bufferId = MemberOrDefault(obj, "buffer", 0); + if (bufferId) { + buffer = r.buffers.Get(bufferId); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", 0u); + byteLength = MemberOrDefault(obj, "byteLength", 0u); +} + + + +inline void Accessor::Read(Value& obj, Asset& r) +{ + const char* bufferViewId = MemberOrDefault(obj, "bufferView", 0); + if (bufferViewId) { + bufferView = r.bufferViews.Get(bufferViewId); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", 0u); + byteStride = MemberOrDefault(obj, "byteStride", 0u); + componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); + count = MemberOrDefault(obj, "count", 0u); + + const char* typestr; + type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; +} + +inline unsigned int Accessor::GetNumComponents() +{ + return AttribType::GetNumComponents(type); +} + +inline unsigned int Accessor::GetBytesPerComponent() +{ + return ComponentTypeSize(componentType); +} + +inline unsigned int Accessor::GetElementSize() +{ + return GetNumComponents() * GetBytesPerComponent(); +} + +inline uint8_t* Accessor::GetPointer() +{ + if (!bufferView || !bufferView->buffer) return 0; + + size_t offset = byteOffset + bufferView->byteOffset; + return bufferView->buffer->GetPointer() + offset; +} + +namespace { + inline void CopyData(size_t count, + const uint8_t* src, size_t src_stride, + uint8_t* dst, size_t dst_stride) + { + if (src_stride == dst_stride) { + memcpy(dst, src, count * src_stride); + } + else { + size_t sz = std::min(src_stride, dst_stride); + for (size_t i = 0; i < count; ++i) { + memcpy(dst, src, sz); + if (sz < dst_stride) { + memset(dst + sz, 0, dst_stride - sz); + } + src += src_stride; + dst += dst_stride; + } + } + } +} + +template +void Accessor::ExtractData(T*& outData) +{ + uint8_t* data = GetPointer(); + ai_assert(data); + + const size_t elemSize = GetElementSize(); + const size_t totalSize = elemSize * count; + + const size_t stride = byteStride ? byteStride : elemSize; + + const size_t targetElemSize = sizeof(T); + ai_assert(elemSize <= targetElemSize); + + ai_assert(count*stride <= bufferView->byteLength); + + outData = new T[count]; + if (stride == elemSize && targetElemSize == elemSize) { + memcpy(outData, data, totalSize); + } + else { + for (size_t i = 0; i < count; ++i) { + memcpy(outData + i, data + i*stride, elemSize); + } + } +} + +inline void Accessor::WriteData(size_t count, const void* src_buffer, size_t src_stride) +{ + uint8_t* buffer_ptr = bufferView->buffer->GetPointer(); + size_t offset = byteOffset + bufferView->byteOffset; + + size_t dst_stride = GetNumComponents() * GetBytesPerComponent(); + + const uint8_t* src = reinterpret_cast(src_buffer); + uint8_t* dst = reinterpret_cast< uint8_t*>(buffer_ptr + offset); + + ai_assert(dst + count*dst_stride <= buffer_ptr + bufferView->buffer->byteLength); + CopyData(count, src, src_stride, dst, dst_stride); +} + + + +inline Accessor::Indexer::Indexer(Accessor& acc) + : accessor(acc) + , data(acc.GetPointer()) + , elemSize(acc.GetElementSize()) + , stride(acc.byteStride ? acc.byteStride : elemSize) +{ + +} + +//! Accesses the i-th value as defined by the accessor +template +T Accessor::Indexer::GetValue(int i) +{ + ai_assert(data); + ai_assert(i*stride < accessor.bufferView->byteLength); + T value = T(); + memcpy(&value, data + i*stride, elemSize); + //value >>= 8 * (sizeof(T) - elemSize); + return value; +} + +inline Image::Image() + : width(0) + , height(0) + , mData(0) + , mDataLength(0) +{ + +} + +inline void Image::Read(Value& obj, Asset& r) +{ + // Check for extensions first (to detect binary embedded data) + if (Value* extensions = FindObject(obj, "extensions")) { + if (r.extensionsUsed.KHR_binary_glTF) { + if (Value* ext = FindObject(*extensions, "KHR_binary_glTF")) { + + width = MemberOrDefault(*ext, "width", 0); + height = MemberOrDefault(*ext, "height", 0); + + ReadMember(*ext, "mimeType", mimeType); + + const char* bufferViewId; + if (ReadMember(*ext, "bufferView", bufferViewId)) { + Ref bv = r.bufferViews.Get(bufferViewId); + if (bv) { + mDataLength = bv->byteLength; + mData = new uint8_t[mDataLength]; + memcpy(mData, bv->buffer->GetPointer() + bv->byteOffset, mDataLength); + } + } + } + } + } + + if (!mDataLength) { + if (Value* uri = FindString(obj, "uri")) { + const char* uristr = uri->GetString(); + + Util::DataURI dataURI; + if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { + mimeType = dataURI.mediaType; + if (dataURI.base64) { + mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, mData); + } + } + else { + this->uri = uristr; + } + } + } +} + +inline uint8_t* Image::StealData() +{ + uint8_t* data = mData; + mDataLength = 0; + mData = 0; + return data; +} + +inline void Image::SetData(uint8_t* data, size_t length, Asset& r) +{ + Ref b = r.GetBodyBuffer(); + if (b) { // binary file: append to body + std::string bvId = r.FindUniqueID(this->id, "imgdata"); + bufferView = r.bufferViews.Create(bvId); + + bufferView->buffer = b; + bufferView->byteLength = length; + bufferView->byteOffset = b->AppendData(data, length); + } + else { // text file: will be stored as a data uri + this->mData = data; + this->mDataLength = length; + } +} + +inline void Texture::Read(Value& obj, Asset& r) +{ + const char* sourcestr; + if (ReadMember(obj, "source", sourcestr)) { + source = r.images.Get(sourcestr); + } +} + +namespace { + inline void ReadMaterialProperty(Asset& r, Value& vals, const char* propName, TexProperty& out) + { + if (Value* prop = FindMember(vals, propName)) { + if (prop->IsString()) { + out.texture = r.textures.Get(prop->GetString()); + } + else { + ReadValue(*prop, out.color); + } + } + } +} + +inline void Material::Read(Value& material, Asset& r) +{ + SetDefaults(); + + if (Value* values = FindObject(material, "values")) { + ReadMaterialProperty(r, *values, "ambient", this->ambient); + ReadMaterialProperty(r, *values, "diffuse", this->diffuse); + ReadMaterialProperty(r, *values, "specular", this->specular); + + ReadMember(*values, "shininess", shininess); + } + + if (Value* extensions = FindObject(material, "extensions")) { + if (r.extensionsUsed.KHR_materials_common) { + if (Value* ext = FindObject(*extensions, "KHR_materials_common")) { + if (Value* tnq = FindString(*ext, "technique")) { + const char* t = tnq->GetString(); + if (strcmp(t, "BLINN") == 0) technique = Technique_BLINN; + else if (strcmp(t, "PHONG") == 0) technique = Technique_PHONG; + else if (strcmp(t, "LAMBERT") == 0) technique = Technique_LAMBERT; + else if (strcmp(t, "CONSTANT") == 0) technique = Technique_CONSTANT; + } + + ReadMaterialProperty(r, *ext, "ambient", this->ambient); + ReadMaterialProperty(r, *ext, "diffuse", this->diffuse); + ReadMaterialProperty(r, *ext, "specular", this->specular); + + ReadMember(*ext, "doubleSided", doubleSided); + ReadMember(*ext, "transparent", transparent); + ReadMember(*ext, "transparency", transparency); + ReadMember(*ext, "shininess", shininess); + } + } + } +} + +namespace { + void SetVector(vec4& v, float x, float y, float z, float w) + { v[0] = x; v[1] = y; v[2] = z; v[3] = w; } +} + +inline void Material::SetDefaults() +{ + SetVector(ambient.color, 0, 0, 0, 1); + SetVector(diffuse.color, 0, 0, 0, 1); + SetVector(specular.color, 0, 0, 0, 1); + SetVector(emission.color, 0, 0, 0, 1); + + doubleSided = false; + transparent = false; + transparency = 1.0; + shininess = 0.0; + + technique = Technique_undefined; +} + +namespace { + + template + inline int Compare(const char* attr, const char (&str)[N]) { + return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0; + } + + inline bool GetAttribVector(Mesh::Primitive& p, const char* attr, Mesh::AccessorList*& v, int& pos) + { + if ((pos = Compare(attr, "POSITION"))) { + v = &(p.attributes.position); + } + else if ((pos = Compare(attr, "NORMAL"))) { + v = &(p.attributes.normal); + } + else if ((pos = Compare(attr, "TEXCOORD"))) { + v = &(p.attributes.texcoord); + } + else if ((pos = Compare(attr, "COLOR"))) { + v = &(p.attributes.color); + } + else if ((pos = Compare(attr, "JOINT"))) { + v = &(p.attributes.joint); + } + else if ((pos = Compare(attr, "JOINTMATRIX"))) { + v = &(p.attributes.jointmatrix); + } + else if ((pos = Compare(attr, "WEIGHT"))) { + v = &(p.attributes.weight); + } + else return false; + return true; + } +} + +inline void Mesh::Read(Value& obj, Asset& r) +{ + if (Value* primitives = FindArray(obj, "primitives")) { + this->primitives.resize(primitives->Size()); + for (unsigned int i = 0; i < primitives->Size(); ++i) { + Value& primitive = (*primitives)[i]; + + Primitive& prim = this->primitives[i]; + prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES); + + if (Value* attrs = FindObject(primitive, "attributes")) { + for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) { + if (!it->value.IsString()) continue; + const char* attr = it->name.GetString(); + // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX, + // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc. + + int undPos = 0; + Mesh::AccessorList* vec = 0; + if (GetAttribVector(prim, attr, vec, undPos)) { + size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; + if ((*vec).size() <= idx) (*vec).resize(idx + 1); + (*vec)[idx] = r.accessors.Get(it->value.GetString()); + } + } + } + + if (Value* indices = FindString(primitive, "indices")) { + prim.indices = r.accessors.Get(indices->GetString()); + } + + if (Value* material = FindString(primitive, "material")) { + prim.material = r.materials.Get(material->GetString()); + } + } + } +} + + +inline void Camera::Read(Value& obj, Asset& r) +{ + type = MemberOrDefault(obj, "type", Camera::Perspective); + + const char* subobjId = (type == Camera::Orthographic) ? "ortographic" : "perspective"; + + Value* it = FindObject(obj, subobjId); + if (!it) throw DeadlyImportError("Camera missing its parameters!"); + + if (type == Camera::Perspective) { + perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f); + perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f); + perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); + perspective.znear = MemberOrDefault(*it, "znear", 0.01f); + } + else { + ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); + ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); + ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); + ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); + } +} + +inline void Light::Read(Value& obj, Asset& r) +{ + SetDefaults(); + + if (Value* type = FindString(obj, "type")) { + const char* t = type->GetString(); + if (strcmp(t, "ambient") == 0) this->type = Type_ambient; + else if (strcmp(t, "directional") == 0) this->type = Type_directional; + else if (strcmp(t, "point") == 0) this->type = Type_point; + else if (strcmp(t, "spot") == 0) this->type = Type_spot; + + if (this->type != Type_undefined) { + if (Value* vals = FindString(obj, t)) { + ReadMember(*vals, "color", color); + + ReadMember(*vals, "constantAttenuation", constantAttenuation); + ReadMember(*vals, "linearAttenuation", linearAttenuation); + ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation); + ReadMember(*vals, "distance", distance); + + ReadMember(*vals, "falloffAngle", falloffAngle); + ReadMember(*vals, "falloffExponent", falloffExponent); + } + } + } +} + +inline void Light::SetDefaults() +{ + #ifndef M_PI + const float M_PI = 3.14159265358979323846f; + #endif + + type = Type_undefined; + + SetVector(color, 0.f, 0.f, 0.f, 1.f); + + constantAttenuation = 0.f; + linearAttenuation = 1.f; + quadraticAttenuation = 1.f; + distance = 0.f; + + falloffAngle = static_cast(M_PI / 2.f); + falloffExponent = 0.f; +} + +inline void Node::Read(Value& obj, Asset& r) +{ + if (Value* children = FindArray(obj, "children")) { + this->children.reserve(children->Size()); + for (unsigned int i = 0; i < children->Size(); ++i) { + Value& child = (*children)[i]; + if (child.IsString()) { + // get/create the child node + Ref chn = r.nodes.Get(child.GetString()); + if (chn) this->children.push_back(chn); + } + } + } + + + if (Value* matrix = FindArray(obj, "matrix")) { + ReadValue(*matrix, this->matrix); + } + else { + ReadMember(obj, "translation", translation); + ReadMember(obj, "scale", scale); + ReadMember(obj, "rotation", rotation); + } + + if (Value* meshes = FindArray(obj, "meshes")) { + size_t numMeshes = (size_t)meshes->Size(); + + std::vector meshList; + + this->meshes.reserve(numMeshes); + for (size_t i = 0; i < numMeshes; ++i) { + if ((*meshes)[i].IsString()) { + Ref mesh = r.meshes.Get((*meshes)[i].GetString()); + if (mesh) this->meshes.push_back(mesh); + } + } + } + + if (Value* camera = FindString(obj, "camera")) { + this->camera = r.cameras.Get(camera->GetString()); + if (this->camera) + this->camera->id = this->id; + } + + // TODO load "skeletons", "skin", "jointName" + + if (Value* extensions = FindObject(obj, "extensions")) { + if (r.extensionsUsed.KHR_materials_common) { + + if (Value* ext = FindObject(*extensions, "KHR_materials_common")) { + if (Value* light = FindString(*ext, "light")) { + this->light = r.lights.Get(light->GetString()); + } + } + + } + } +} + +inline void Scene::Read(Value& obj, Asset& r) +{ + if (Value* array = FindArray(obj, "nodes")) { + for (unsigned int i = 0; i < array->Size(); ++i) { + if (!(*array)[i].IsString()) continue; + Ref node = r.nodes.Get((*array)[i].GetString()); + if (node) + this->nodes.push_back(node); + } + } +} + + +inline void AssetMetadata::Read(Document& doc) +{ + // read the version, etc. + int statedVersion = 0; + if (Value* obj = FindObject(doc, "asset")) { + ReadMember(*obj, "copyright", copyright); + ReadMember(*obj, "generator", generator); + + premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false); + statedVersion = MemberOrDefault(*obj, "version", 0); + + if (Value* profile = FindObject(*obj, "profile")) { + ReadMember(*profile, "api", this->profile.api); + ReadMember(*profile, "version", this->profile.version); + } + } + + version = std::max(statedVersion, version); + if (version == 0) { + // if missing version, we'll assume version 1... + version = 1; + } + + if (version != 1) { + char msg[128]; + ai_snprintf(msg, 128, "Unsupported glTF version: %d", version); + throw DeadlyImportError(msg); + } +} + + + +// +// Asset methods implementation +// + +inline void Asset::ReadBinaryHeader(IOStream& stream) +{ + GLB_Header header; + if (stream.Read(&header, sizeof(header), 1) != 1) { + throw DeadlyImportError("Unable to read the file header"); + } + + if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) { + throw DeadlyImportError("Invalid binary glTF file"); + } + + AI_SWAP4(header.version); + asset.version = header.version; + if (header.version != 1) { + throw DeadlyImportError("Unsupported binary glTF version"); + } + + AI_SWAP4(header.sceneFormat); + if (header.sceneFormat != SceneFormat_JSON) { + throw DeadlyImportError("Unsupported binary glTF scene format"); + } + + AI_SWAP4(header.length); + AI_SWAP4(header.sceneLength); + + mSceneLength = static_cast(header.sceneLength); + + mBodyOffset = sizeof(header)+mSceneLength; + mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4 + + mBodyLength = header.length - mBodyOffset; +} + +inline void Asset::Load(const std::string& pFile, bool isBinary) +{ + mCurrentAssetDir.clear(); + int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); + if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1); + + shared_ptr stream(OpenFile(pFile.c_str(), "rb", true)); + if (!stream) { + throw DeadlyImportError("Could not open file for reading"); + } + + // is binary? then read the header + if (isBinary) { + SetAsBinary(); // also creates the body buffer + ReadBinaryHeader(*stream); + } + else { + mSceneLength = stream->FileSize(); + mBodyLength = 0; + } + + + // read the scene data + + std::vector sceneData(mSceneLength + 1); + sceneData[mSceneLength] = '\0'; + + if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) { + throw DeadlyImportError("Could not read the file contents"); + } + + + // parse the JSON document + + Document doc; + doc.ParseInsitu(&sceneData[0]); + + if (doc.HasParseError()) { + char buffer[32]; + ai_snprintf(buffer, 32, "%d", static_cast(doc.GetErrorOffset())); + throw DeadlyImportError(std::string("JSON parse error, offset ") + buffer + ": " + + GetParseError_En(doc.GetParseError())); + } + + if (!doc.IsObject()) { + throw DeadlyImportError("gltf file must be a JSON object!"); + } + + // Fill the buffer instance for the current file embedded contents + if (mBodyLength > 0) { + mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset); + } + + + // Load the metadata + asset.Read(doc); + ReadExtensionsUsed(doc); + + // Prepare the dictionaries + for (size_t i = 0; i < mDicts.size(); ++i) { + mDicts[i]->AttachToDocument(doc); + } + + + + // Read the "scene" property, which specifies which scene to load + // and recursively load everything referenced by it + if (Value* scene = FindString(doc, "scene")) { + this->scene = scenes.Get(scene->GetString()); + } + + // Clean up + for (size_t i = 0; i < mDicts.size(); ++i) { + mDicts[i]->DetachFromDocument(); + } +} + +inline void Asset::SetAsBinary() +{ + if (!extensionsUsed.KHR_binary_glTF) { + extensionsUsed.KHR_binary_glTF = true; + mBodyBuffer = buffers.Create("KHR_binary_glTF"); + mBodyBuffer->MarkAsSpecial(); + } +} + + +inline void Asset::ReadExtensionsUsed(Document& doc) +{ + Value* extsUsed = FindArray(doc, "extensionsUsed"); + if (!extsUsed) return; + + std::gltf_unordered_map exts; + + for (unsigned int i = 0; i < extsUsed->Size(); ++i) { + if ((*extsUsed)[i].IsString()) { + exts[(*extsUsed)[i].GetString()] = true; + } + } + + #define CHECK_EXT(EXT) \ + if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; + + CHECK_EXT(KHR_binary_glTF); + CHECK_EXT(KHR_materials_common); + + #undef CHECK_EXT +} + +inline IOStream* Asset::OpenFile(std::string path, const char* mode, bool absolute) +{ + #ifdef ASSIMP_API + return mIOSystem->Open(path, mode); + #else + if (path.size() < 2) return 0; + if (!absolute && path[1] != ':' && path[0] != '/') { // relative? + path = mCurrentAssetDir + path; + } + FILE* f = fopen(path.c_str(), mode); + return f ? new IOStream(f) : 0; + #endif +} + +inline std::string Asset::FindUniqueID(const std::string& str, const char* suffix) +{ + std::string id = str; + + Asset::IdMap::iterator it; + + do { + if (!id.empty()) { + it = mUsedIds.find(id); + if (it == mUsedIds.end()) break; + + id += "_"; + } + + id += suffix; + + it = mUsedIds.find(id); + if (it == mUsedIds.end()) break; + + char buffer[256]; + int offset = ai_snprintf(buffer, 256, "%s_", id.c_str()); + for (int i = 0; it != mUsedIds.end(); ++i) { + ai_snprintf(buffer + offset, 256, "%d", i); + + id = buffer; + it = mUsedIds.find(id); + } + } while (false); // fake loop to allow using "break" + + return id; +} + +namespace Util { + + inline + bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { + if ( NULL == const_uri ) { + return false; + } + + if (const_uri[0] != 0x10) { // we already parsed this uri? + if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? + return false; + } + + // set defaults + out.mediaType = "text/plain"; + out.charset = "US-ASCII"; + out.base64 = false; + + char* uri = const_cast(const_uri); + if (uri[0] != 0x10) { + uri[0] = 0x10; + uri[1] = uri[2] = uri[3] = uri[4] = 0; + + size_t i = 5, j; + if (uri[i] != ';' && uri[i] != ',') { // has media type? + uri[1] = i; + for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + } + while (uri[i] == ';' && i < uriLen) { + uri[i++] = '\0'; + for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + + if ( strncmp( uri + j, "charset=", 8 ) == 0 ) { + uri[ 2 ] = j + 8; + } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) { + uri[ 3 ] = j; + } + } + if (i < uriLen) { + uri[i++] = '\0'; + uri[4] = i; + } else { + uri[1] = uri[2] = uri[3] = 0; + uri[4] = 5; + } + } + + if ( uri[ 1 ] != 0 ) { + out.mediaType = uri + uri[ 1 ]; + } + if ( uri[ 2 ] != 0 ) { + out.charset = uri + uri[ 2 ]; + } + if ( uri[ 3 ] != 0 ) { + out.base64 = true; + } + out.data = uri + uri[4]; + out.dataLength = (uri + uriLen) - out.data; + + return true; + } + + template + struct DATA + { + static const uint8_t tableDecodeBase64[128]; + }; + + template + const uint8_t DATA::tableDecodeBase64[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 + }; + + inline char EncodeCharBase64(uint8_t b) + { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; + } + + inline uint8_t DecodeCharBase64(char c) + { + return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? + /*if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + return 64; // '-' */ + } + + inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) + { + ai_assert(inLength % 4 == 0); + + if (inLength < 4) { + out = 0; + return 0; + } + + int nEquals = int(in[inLength - 1] == '=') + + int(in[inLength - 2] == '='); + + size_t outLength = (inLength * 3) / 4 - nEquals; + out = new uint8_t[outLength]; + memset(out, 0, outLength); + + size_t i, j = 0; + + for (i = 0; i + 4 < inLength; i += 4) { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + out[j++] = (uint8_t)((b2 << 6) | b3); + } + + { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); + } + + return outLength; + } + + + + inline void EncodeBase64( + const uint8_t* in, size_t inLength, + std::string& out) + { + size_t outLength = ((inLength + 2) / 3) * 4; + + size_t j = out.size(); + out.resize(j + outLength); + + for (size_t i = 0; i < inLength; i += 3) { + uint8_t b = (in[i] & 0xFC) >> 2; + out[j++] = EncodeCharBase64(b); + + b = (in[i] & 0x03) << 4; + if (i + 1 < inLength) { + b |= (in[i + 1] & 0xF0) >> 4; + out[j++] = EncodeCharBase64(b); + + b = (in[i + 1] & 0x0F) << 2; + if (i + 2 < inLength) { + b |= (in[i + 2] & 0xC0) >> 6; + out[j++] = EncodeCharBase64(b); + + b = in[i + 2] & 0x3F; + out[j++] = EncodeCharBase64(b); + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + } + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + out[j++] = '='; + } + } + } + +} + +} + + diff --git a/code/glTFAssetWriter.h b/code/glTFAssetWriter.h new file mode 100644 index 000000000..4ddae7d53 --- /dev/null +++ b/code/glTFAssetWriter.h @@ -0,0 +1,89 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 glTFWriter.h + * Declares a class to write gltf/glb files + * + * glTF Extensions Support: + * KHR_binary_glTF: full + * KHR_materials_common: full + */ +#ifndef glTFAssetWriter_H_INC +#define glTFAssetWriter_H_INC + +#include "glTFAsset.h" + +namespace glTF +{ + +using rapidjson::MemoryPoolAllocator; + +class AssetWriter +{ + template + friend struct LazyDictWriter; + +private: + + void WriteBinaryData(IOStream* outfile, size_t sceneLength); + + void WriteMetadata(); + void WriteExtensionsUsed(); + + template + void WriteObjects(LazyDict& d); + +public: + Document mDoc; + Asset& mAsset; + + MemoryPoolAllocator<>& mAl; + + AssetWriter(Asset& asset); + + void WriteFile(const char* path); +}; + +} + +// Include the implementation of the methods +#include "glTFAssetWriter.inl" + +#endif diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl new file mode 100644 index 000000000..9f990ca36 --- /dev/null +++ b/code/glTFAssetWriter.inl @@ -0,0 +1,497 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 +#include +#include + +namespace glTF { + + using rapidjson::StringBuffer; + using rapidjson::PrettyWriter; + using rapidjson::Writer; + using rapidjson::StringRef; + using rapidjson::StringRef; + + namespace { + + template + inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + val.SetArray(); + val.Reserve(N, al); + for (int i = 0; i < N; ++i) { + val.PushBack(r[i], al); + } + return val; + }; + + template + inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref >& v, MemoryPoolAllocator<>& al) { + if (v.empty()) return; + Value lst; + lst.SetArray(); + lst.Reserve(v.size(), al); + for (size_t i = 0; i < v.size(); ++i) { + lst.PushBack(StringRef(v[i]->id), al); + } + obj.AddMember(StringRef(fieldId), lst, al); + }; + + + } + + inline void Write(Value& obj, Accessor& a, AssetWriter& w) + { + obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl); + obj.AddMember("byteOffset", a.byteOffset, w.mAl); + obj.AddMember("byteStride", a.byteStride, w.mAl); + obj.AddMember("componentType", int(a.componentType), w.mAl); + obj.AddMember("count", a.count, w.mAl); + obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); + } + + inline void Write(Value& obj, Animation& a, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Buffer& b, AssetWriter& w) + { + std::string dataURI = "data:application/octet-stream;base64,"; + Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI); + + const char* type; + switch (b.type) { + case Buffer::Type_text: + type = "text"; break; + default: + type = "arraybuffer"; + } + + obj.AddMember("byteLength", b.byteLength, w.mAl); + obj.AddMember("type", StringRef(type), w.mAl); + obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl); + } + + inline void Write(Value& obj, BufferView& bv, AssetWriter& w) + { + obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl); + obj.AddMember("byteOffset", bv.byteOffset, w.mAl); + obj.AddMember("byteLength", bv.byteLength, w.mAl); + obj.AddMember("target", int(bv.target), w.mAl); + } + + inline void Write(Value& obj, Camera& c, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Image& img, AssetWriter& w) + { + std::string uri; + if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) { + Value exts, ext; + exts.SetObject(); + ext.SetObject(); + + ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl); + + if (!img.mimeType.empty()) + ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl); + + exts.AddMember("KHR_binary_glTF", ext, w.mAl); + obj.AddMember("extensions", exts, w.mAl); + return; + } + else if (img.HasData()) { + uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); + uri += ";base64,"; + Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + } + else { + uri = img.uri; + } + + obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl); + } + + namespace { + inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al) + { + if (prop.texture) + obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al); + else { + Value col; + obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al); + } + } + } + + inline void Write(Value& obj, Material& m, AssetWriter& w) + { + Value v; + v.SetObject(); + { + WriteColorOrTex(v, m.ambient, "ambient", w.mAl); + WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl); + WriteColorOrTex(v, m.specular, "specular", w.mAl); + WriteColorOrTex(v, m.emission, "emission", w.mAl); + + v.AddMember("shininess", m.shininess, w.mAl); + } + obj.AddMember("values", v, w.mAl); + } + + namespace { + inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst, + const char* semantic, bool forceNumber = false) + { + if (lst.empty()) return; + if (lst.size() == 1 && !forceNumber) { + attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl); + } + else { + for (size_t i = 0; i < lst.size(); ++i) { + char buffer[32]; + ai_snprintf(buffer, 32, "%s_%d", semantic, int(i)); + attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl); + } + } + } + } + + inline void Write(Value& obj, Mesh& m, AssetWriter& w) + { + Value primitives; + primitives.SetArray(); + primitives.Reserve(m.primitives.size(), w.mAl); + + for (size_t i = 0; i < m.primitives.size(); ++i) { + Mesh::Primitive& p = m.primitives[i]; + Value prim; + prim.SetObject(); + { + prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl); + + if (p.material) + prim.AddMember("material", p.material->id, w.mAl); + + if (p.indices) + prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl); + + Value attrs; + attrs.SetObject(); + { + WriteAttrs(w, attrs, p.attributes.position, "POSITION"); + WriteAttrs(w, attrs, p.attributes.normal, "NORMAL"); + WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true); + WriteAttrs(w, attrs, p.attributes.color, "COLOR"); + WriteAttrs(w, attrs, p.attributes.joint, "JOINT"); + WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX"); + WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT"); + } + prim.AddMember("attributes", attrs, w.mAl); + } + primitives.PushBack(prim, w.mAl); + } + + obj.AddMember("primitives", primitives, w.mAl); + } + + inline void Write(Value& obj, Node& n, AssetWriter& w) + { + + if (n.matrix.isPresent) { + Value val; + obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl); + } + + if (n.translation.isPresent) { + Value val; + obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl); + } + + if (n.scale.isPresent) { + Value val; + obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl); + } + if (n.rotation.isPresent) { + Value val; + obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl); + } + + AddRefsVector(obj, "children", n.children, w.mAl); + + AddRefsVector(obj, "meshes", n.meshes, w.mAl); + } + + inline void Write(Value& obj, Program& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Sampler& b, AssetWriter& w) + { + + } + + inline void Write(Value& scene, Scene& s, AssetWriter& w) + { + AddRefsVector(scene, "nodes", s.nodes, w.mAl); + } + + inline void Write(Value& obj, Shader& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Skin& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Technique& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Texture& tex, AssetWriter& w) + { + if (tex.source) { + obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl); + } + } + + inline void Write(Value& obj, Light& b, AssetWriter& w) + { + + } + + + AssetWriter::AssetWriter(Asset& a) + : mDoc() + , mAsset(a) + , mAl(mDoc.GetAllocator()) + { + mDoc.SetObject(); + + WriteMetadata(); + WriteExtensionsUsed(); + + // Dump the contents of the dictionaries + for (size_t i = 0; i < a.mDicts.size(); ++i) { + a.mDicts[i]->WriteObjects(*this); + } + + // Add the target scene field + if (mAsset.scene) { + mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl); + } + } + + void AssetWriter::WriteFile(const char* path) + { + bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF; + + boost::scoped_ptr outfile + (mAsset.OpenFile(path, isBinary ? "wb" : "wt", true)); + + if (outfile == 0) { + throw DeadlyExportError("Could not open output file: " + std::string(path)); + } + + if (isBinary) { + // we will write the header later, skip its size + outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); + } + + StringBuffer docBuffer; + + bool pretty = true; + if (!isBinary && pretty) { + PrettyWriter writer(docBuffer); + mDoc.Accept(writer); + } + else { + Writer writer(docBuffer); + mDoc.Accept(writer); + } + + if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { + throw DeadlyExportError("Failed to write scene data!"); + } + + if (isBinary) { + WriteBinaryData(outfile.get(), docBuffer.GetSize()); + } + } + + void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength) + { + // + // write the body data + // + + size_t bodyLength = 0; + if (Ref b = mAsset.GetBodyBuffer()) { + bodyLength = b->byteLength; + + if (bodyLength > 0) { + size_t bodyOffset = sizeof(GLB_Header) + sceneLength; + bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4 + + outfile->Seek(bodyOffset, aiOrigin_SET); + + if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) { + throw DeadlyExportError("Failed to write body data!"); + } + } + } + + + // + // write the header + // + + GLB_Header header; + memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)); + + header.version = 1; + AI_SWAP4(header.version); + + header.length = sizeof(header) + sceneLength + bodyLength; + AI_SWAP4(header.length); + + header.sceneLength = sceneLength; + AI_SWAP4(header.sceneLength); + + header.sceneFormat = SceneFormat_JSON; + AI_SWAP4(header.sceneFormat); + + outfile->Seek(0, aiOrigin_SET); + + if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) { + throw DeadlyExportError("Failed to write the header!"); + } + } + + + void AssetWriter::WriteMetadata() + { + Value asset; + asset.SetObject(); + { + asset.AddMember("version", mAsset.asset.version, mAl); + + asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl); + } + mDoc.AddMember("asset", asset, mAl); + } + + void AssetWriter::WriteExtensionsUsed() + { + Value exts; + exts.SetArray(); + { + if (false) + exts.PushBack(StringRef("KHR_binary_glTF"), mAl); + + if (false) + exts.PushBack(StringRef("KHR_materials_common"), mAl); + } + + if (!exts.Empty()) + mDoc.AddMember("extensionsUsed", exts, mAl); + } + + template + void AssetWriter::WriteObjects(LazyDict& d) + { + if (d.mObjs.empty()) return; + + Value* container = &mDoc; + + if (d.mExtId) { + Value* exts = FindObject(mDoc, "extensions"); + if (!exts) { + mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator()); + exts = FindObject(mDoc, "extensions"); + } + + if (!(container = FindObject(*exts, d.mExtId))) { + exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator()); + container = FindObject(*exts, d.mExtId); + } + } + + Value* dict; + if (!(dict = FindObject(*container, d.mDictId))) { + container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator()); + dict = FindObject(*container, d.mDictId); + } + + for (size_t i = 0; i < d.mObjs.size(); ++i) { + if (d.mObjs[i]->IsSpecial()) continue; + + Value obj; + obj.SetObject(); + + if (!d.mObjs[i]->name.empty()) { + obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl); + } + + Write(obj, *d.mObjs[i], *this); + + dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl); + } + } + + template + struct LazyDictWriter< LazyDict > + { + static void Write(LazyDict& d, AssetWriter& w) + { + w.WriteObjects(d); + } + }; + +} + + diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp new file mode 100644 index 000000000..41cdaf084 --- /dev/null +++ b/code/glTFExporter.cpp @@ -0,0 +1,367 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER + +#include "glTFExporter.h" +#include "Exceptional.h" +#include "StringComparison.h" +#include "ByteSwapper.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "glTFAssetWriter.h" + +using namespace rapidjson; + +using namespace Assimp; +using namespace glTF; + +namespace Assimp { + + // ------------------------------------------------------------------------------------------------ + // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp + void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) + { + // invoke the exporter + glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false); + } + + // ------------------------------------------------------------------------------------------------ + // Worker function for exporting a scene to GLB. Prototyped and registered in Exporter.cpp + void ExportSceneGLB(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) + { + // invoke the exporter + glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, true); + } + +} // end of namespace Assimp + + + +glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool isBinary) + : mFilename(filename) + , mIOSystem(pIOSystem) + , mScene(pScene) + , mProperties(pProperties) +{ + boost::scoped_ptr asset(new glTF::Asset(pIOSystem)); + mAsset = asset.get(); + + if (isBinary) { + asset->SetAsBinary(); + } + + ExportMetadata(); + + //for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {} + + //for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {} + + //for (unsigned int i = 0; i < pScene->mNumLights; ++i) {} + + + ExportMaterials(); + + ExportMeshes(); + + //for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {} + + + if (mScene->mRootNode) { + ExportNode(mScene->mRootNode); + } + + ExportScene(); + + + glTF::AssetWriter writer(*mAsset); + writer.WriteFile(filename); +} + + +static void CopyValue(const aiMatrix4x4& v, glTF::mat4& o) +{ + o[ 0] = v.a1; o[ 1] = v.b1; o[ 2] = v.c1; o[ 3] = v.d1; + o[ 4] = v.a2; o[ 5] = v.b2; o[ 6] = v.c2; o[ 7] = v.d2; + o[ 8] = v.a3; o[ 9] = v.b3; o[10] = v.c3; o[11] = v.d3; + o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4; +} + +inline Ref ExportData(Asset& a, std::string& meshName, Ref& buffer, + unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) +{ + if (!count || !data) return Ref(); + + unsigned int numCompsIn = AttribType::GetNumComponents(typeIn); + unsigned int numCompsOut = AttribType::GetNumComponents(typeOut); + unsigned int bytesPerComp = ComponentTypeSize(compType); + + size_t offset = buffer->byteLength; + size_t length = count * numCompsOut * bytesPerComp; + buffer->Grow(length); + + // bufferView + Ref bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view")); + bv->buffer = buffer; + bv->byteOffset = 0; + bv->byteLength = length; //! The target that the WebGL buffer should be bound to. + bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER; + + // accessor + Ref acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor")); + acc->bufferView = bv; + acc->byteOffset = offset; + acc->byteStride = 0; + acc->componentType = compType; + acc->count = count; + acc->type = typeOut; + + // copy the data + acc->WriteData(count, data, numCompsIn*bytesPerComp); + + return acc; +} + +namespace { + void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) { + if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {} + } +} + +void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt) +{ + aiString tex; + aiColor4D col; + if (mat->GetTextureCount(tt) > 0) { + if (mat->Get(AI_MATKEY_TEXTURE(tt, 0), tex) == AI_SUCCESS) { + std::string path = tex.C_Str(); + + if (path.size() > 0) { + if (path[0] != '*') { + std::map::iterator it = mTexturesByPath.find(path); + if (it != mTexturesByPath.end()) { + prop.texture = mAsset->textures.Get(it->second); + } + } + + if (!prop.texture) { + std::string texId = mAsset->FindUniqueID("", "texture"); + prop.texture = mAsset->textures.Create(texId); + mTexturesByPath[path] = prop.texture.GetIndex(); + + std::string imgId = mAsset->FindUniqueID("", "image"); + prop.texture->source = mAsset->images.Create(imgId); + + if (path[0] == '*') { // embedded + aiTexture* tex = mScene->mTextures[atoi(&path[1])]; + + uint8_t* data = reinterpret_cast(tex->pcData); + prop.texture->source->SetData(data, tex->mWidth, *mAsset); + + if (tex->achFormatHint[0]) { + std::string mimeType = "image/"; + mimeType += (memcmp(tex->achFormatHint, "jpg", 3) == 0) ? "jpeg" : tex->achFormatHint; + prop.texture->source->mimeType = mimeType; + } + } + else { + prop.texture->source->uri = path; + } + } + } + } + } + + if (mat->Get(propName, type, idx, col) == AI_SUCCESS) { + prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a; + } +} + +void glTFExporter::ExportMaterials() +{ + aiString aiName; + for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { + const aiMaterial* mat = mScene->mMaterials[i]; + + + std::string name; + if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) { + name = aiName.C_Str(); + } + name = mAsset->FindUniqueID(name, "material"); + + Ref m = mAsset->materials.Create(name); + + GetMatColorOrTex(mat, m->ambient, AI_MATKEY_COLOR_AMBIENT, aiTextureType_AMBIENT); + GetMatColorOrTex(mat, m->diffuse, AI_MATKEY_COLOR_DIFFUSE, aiTextureType_DIFFUSE); + GetMatColorOrTex(mat, m->specular, AI_MATKEY_COLOR_SPECULAR, aiTextureType_SPECULAR); + GetMatColorOrTex(mat, m->emission, AI_MATKEY_COLOR_EMISSIVE, aiTextureType_EMISSIVE); + + GetMatScalar(mat, m->shininess, AI_MATKEY_SHININESS); + } +} + +void glTFExporter::ExportMeshes() +{ + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { + const aiMesh* aim = mScene->mMeshes[i]; + + std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh"); + Ref m = mAsset->meshes.Create(meshId); + m->primitives.resize(1); + Mesh::Primitive& p = m->primitives.back(); + + p.material = mAsset->materials.Get(aim->mMaterialIndex); + + std::string bufferId = mAsset->FindUniqueID(meshId, "buffer"); + + Ref b = mAsset->GetBodyBuffer(); + if (!b) { + b = mAsset->buffers.Create(bufferId); + } + + Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if (v) p.attributes.position.push_back(v); + + Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if (n) p.attributes.normal.push_back(n); + + for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (aim->mNumUVComponents[i] > 0) { + AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; + Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true); + if (tc) p.attributes.texcoord.push_back(tc); + } + } + + if (aim->mNumFaces > 0) { + unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices; + std::vector indices; + indices.resize(aim->mNumFaces * nIndicesPerFace); + for (size_t i = 0; i < aim->mNumFaces; ++i) { + for (size_t j = 0; j < nIndicesPerFace; ++j) { + indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]); + } + } + p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT); + } + + switch (aim->mPrimitiveTypes) { + case aiPrimitiveType_POLYGON: + p.mode = PrimitiveMode_TRIANGLES; break; // TODO implement this + case aiPrimitiveType_LINE: + p.mode = PrimitiveMode_LINES; break; + case aiPrimitiveType_POINT: + p.mode = PrimitiveMode_POINTS; break; + default: // aiPrimitiveType_TRIANGLE + p.mode = PrimitiveMode_TRIANGLES; + } + } +} + +size_t glTFExporter::ExportNode(const aiNode* n) +{ + Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); + + if (!n->mTransformation.IsIdentity()) { + node->matrix.isPresent = true; + CopyValue(n->mTransformation, node->matrix.value); + } + + for (unsigned int i = 0; i < n->mNumMeshes; ++i) { + node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); + } + + for (unsigned int i = 0; i < n->mNumChildren; ++i) { + size_t idx = ExportNode(n->mChildren[i]); + node->children.push_back(mAsset->nodes.Get(idx)); + } + + return node.GetIndex(); +} + + +void glTFExporter::ExportScene() +{ + const char* sceneName = "defaultScene"; + Ref scene = mAsset->scenes.Create(sceneName); + + // root node will be the first one exported (idx 0) + if (mAsset->nodes.Size() > 0) { + scene->nodes.push_back(mAsset->nodes.Get(size_t(0))); + } + + // set as the default scene + mAsset->scene = scene; +} + +void glTFExporter::ExportMetadata() +{ + glTF::AssetMetadata& asset = mAsset->asset; + asset.version = 1; + + char buffer[256]; + ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)", + aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision()); + + asset.generator = buffer; +} + + + + + + + +#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/glTFExporter.h b/code/glTFExporter.h new file mode 100644 index 000000000..57746b6f6 --- /dev/null +++ b/code/glTFExporter.h @@ -0,0 +1,108 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 GltfExporter.h +* Declares the exporter class to write a scene to a gltf/glb file +*/ +#ifndef AI_GLTFEXPORTER_H_INC +#define AI_GLTFEXPORTER_H_INC + +#include +#include +#include +#include +#include + +#include "boost/scoped_ptr.hpp" + + +struct aiScene; +struct aiNode; +struct aiMaterial; + +namespace glTF +{ + class Asset; + + struct TexProperty; +} + +namespace Assimp +{ + class IOSystem; + class IOStream; + class ExportProperties; + + // ------------------------------------------------------------------------------------------------ + /** Helper class to export a given scene to an glTF file. */ + // ------------------------------------------------------------------------------------------------ + class glTFExporter + { + public: + /// Constructor for a specific scene to export + glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool binary); + + private: + + const char* mFilename; + IOSystem* mIOSystem; + const aiScene* mScene; + const ExportProperties* mProperties; + + std::map mTexturesByPath; + + glTF::Asset* mAsset; + + std::vector mBodyData; + + void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); + + void GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt); + void ExportMetadata(); + void ExportMaterials(); + void ExportMeshes(); + size_t ExportNode(const aiNode* node); + void ExportScene(); + }; + +} + +#endif diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp new file mode 100644 index 000000000..2bfd5709a --- /dev/null +++ b/code/glTFImporter.cpp @@ -0,0 +1,630 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include "glTFImporter.h" + +#include "StringComparison.h" + +#include "boost/scoped_ptr.hpp" + +#include +#include +#include +#include +#include + +#include "glTFAsset.h" + +using namespace Assimp; +using namespace glTF; + + +// +// glTFImporter +// + +static const aiImporterDesc desc = { + "glTF Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour + | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "gltf glb" +}; + +glTFImporter::glTFImporter() +: BaseImporter() +, meshOffsets() +, embeddedTexIdxs() +, mScene( NULL ) { + // empty +} + +glTFImporter::~glTFImporter() { + // empty +} + +const aiImporterDesc* glTFImporter::GetInfo() const +{ + return &desc; +} + +bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const +{ + const std::string& extension = GetExtension(pFile); + + if (extension == "gltf" || extension == "glb") + return true; + + if ((checkSig || !extension.length()) && pIOHandler) { + char buffer[4]; + + boost::scoped_ptr pStream(pIOHandler->Open(pFile)); + if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) { + if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) { + return true; // Has GLB header + } + else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0 + || memcmp(buffer, "{\n ", sizeof(buffer)) == 0) { + // seems a JSON file, and we're the only format that can read them + return true; + } + } + } + + return false; +} + + + +//static void CopyValue(const glTF::vec3& v, aiColor3D& out) +//{ +// out.r = v[0]; out.g = v[1]; out.b = v[2]; +//} + +static void CopyValue(const glTF::vec4& v, aiColor4D& out) +{ + out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3]; +} + +static void CopyValue(const glTF::vec4& v, aiColor3D& out) +{ + out.r = v[0]; out.g = v[1]; out.b = v[2]; +} + +static void CopyValue(const glTF::vec3& v, aiVector3D& out) +{ + out.x = v[0]; out.y = v[1]; out.z = v[2]; +} + +static void CopyValue(const glTF::vec4& v, aiQuaternion& out) +{ + out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3]; +} + +static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o) +{ + o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3]; + o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7]; + o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11]; + o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; +} + +inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& r, glTF::TexProperty prop, aiMaterial* mat, + aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx) +{ + if (prop.texture) { + if (prop.texture->source) { + aiString uri(prop.texture->source->uri); + + int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; + if (texIdx != -1) { // embedded + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + uri.data[0] = '*'; + uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); + } + + mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0); + } + } + else { + aiColor4D col; + CopyValue(prop.color, col); + if (col.r != 1.f || col.g != 1.f || col.b != 1.f || col.a != 1.f) { + mat->AddProperty(&col, 1, pKey, type, idx); + } + } +} + +void glTFImporter::ImportMaterials(glTF::Asset& r) +{ + mScene->mNumMaterials = r.materials.Size(); + mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials]; + + for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { + aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial(); + + Material& mat = r.materials[i]; + + /*if (!mat.name.empty())*/ { + aiString str(mat.id /*mat.name*/); + aimat->AddProperty(&str, AI_MATKEY_NAME); + } + + SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); + SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); + + if (mat.shininess > 0.f) { + aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS); + } + } + + if (mScene->mNumMaterials == 0) { + mScene->mNumMaterials = 1; + mScene->mMaterials = new aiMaterial*[1]; + mScene->mMaterials[0] = new aiMaterial(); + } +} + + +inline void SetFace(aiFace& face, int a) +{ + face.mNumIndices = 1; + face.mIndices = new unsigned int[1]; + face.mIndices[0] = a; +} + +inline void SetFace(aiFace& face, int a, int b) +{ + face.mNumIndices = 2; + face.mIndices = new unsigned int[2]; + face.mIndices[0] = a; + face.mIndices[1] = b; +} + +inline void SetFace(aiFace& face, int a, int b, int c) +{ + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = a; + face.mIndices[1] = b; + face.mIndices[2] = c; +} + +void glTFImporter::ImportMeshes(glTF::Asset& r) +{ + std::vector meshes; + + unsigned int k = 0; + + for (unsigned int m = 0; m < r.meshes.Size(); ++m) { + Mesh& mesh = r.meshes[m]; + + meshOffsets.push_back(k); + k += mesh.primitives.size(); + + for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { + Mesh::Primitive& prim = mesh.primitives[p]; + + aiMesh* aim = new aiMesh(); + meshes.push_back(aim); + + aim->mName = mesh.id; + if (mesh.primitives.size() > 1) { + size_t& len = aim->mName.length; + aim->mName.data[len] = '-'; + len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, MAXLEN - len - 1, p); + } + + switch (prim.mode) { + case PrimitiveMode_POINTS: + aim->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + + case PrimitiveMode_LINES: + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: + aim->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + + case PrimitiveMode_TRIANGLES: + case PrimitiveMode_TRIANGLE_STRIP: + case PrimitiveMode_TRIANGLE_FAN: + aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + } + + Mesh::Primitive::Attributes& attr = prim.attributes; + if (attr.position.size() > 0 && attr.position[0]) { + aim->mNumVertices = attr.position[0]->count; + attr.position[0]->ExtractData(aim->mVertices); + } + + if (attr.normal.size() > 0 && attr.normal[0]) { + attr.normal[0]->ExtractData(aim->mNormals); + } + + for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { + attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); + aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); + } + + + if (prim.indices) { + aiFace* faces = 0; + size_t nFaces = 0; + + unsigned int count = prim.indices->count; + + Accessor::Indexer data = prim.indices->GetIndexer(); + + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFace(faces[i], data.GetUInt(i)); + } + break; + } + + case PrimitiveMode_LINES: { + nFaces = count / 2; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); + } + break; + } + + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1)); + for (unsigned int i = 2; i < count; ++i) { + SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i)); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); + } + break; + } + + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 3; i < count; ++i) { + SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i)); + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 3; i < count; ++i) { + SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i)); + } + break; + } + + if (faces) { + aim->mFaces = faces; + aim->mNumFaces = nFaces; + } + } + + + if (prim.material) { + aim->mMaterialIndex = prim.material.GetIndex(); + } + } + } + + meshOffsets.push_back(k); + + CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); +} + +void glTFImporter::ImportCameras(glTF::Asset& r) +{ + if (!r.cameras.Size()) return; + + mScene->mNumCameras = r.cameras.Size(); + mScene->mCameras = new aiCamera*[r.cameras.Size()]; + + for (size_t i = 0; i < r.cameras.Size(); ++i) { + Camera& cam = r.cameras[i]; + + aiCamera* aicam = mScene->mCameras[i] = new aiCamera(); + + if (cam.type == Camera::Perspective) { + + aicam->mAspect = cam.perspective.aspectRatio; + aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect; + aicam->mClipPlaneFar = cam.perspective.zfar; + aicam->mClipPlaneNear = cam.perspective.znear; + } + else { + // assimp does not support orthographic cameras + } + } +} + +void glTFImporter::ImportLights(glTF::Asset& r) +{ + if (!r.lights.Size()) return; + + mScene->mNumLights = r.lights.Size(); + mScene->mLights = new aiLight*[r.lights.Size()]; + + for (size_t i = 0; i < r.lights.Size(); ++i) { + Light& l = r.lights[i]; + + aiLight* ail = mScene->mLights[i] = new aiLight(); + + switch (l.type) { + case Light::Type_directional: + ail->mType = aiLightSource_DIRECTIONAL; break; + + case Light::Type_spot: + ail->mType = aiLightSource_SPOT; break; + + case Light::Type_ambient: + ail->mType = aiLightSource_AMBIENT; break; + + default: // Light::Type_point + ail->mType = aiLightSource_POINT; break; + } + + CopyValue(l.color, ail->mColorAmbient); + CopyValue(l.color, ail->mColorDiffuse); + CopyValue(l.color, ail->mColorSpecular); + + ail->mAngleOuterCone = l.falloffAngle; + ail->mAngleInnerCone = l.falloffExponent; // TODO fix this, it does not look right at all + + ail->mAttenuationConstant = l.constantAttenuation; + ail->mAttenuationLinear = l.linearAttenuation; + ail->mAttenuationQuadratic = l.quadraticAttenuation; + } +} + + +aiNode* ImportNode(aiScene* pScene, glTF::Asset& r, std::vector& meshOffsets, glTF::Ref& ptr) +{ + Node& node = *ptr; + + aiNode* ainode = new aiNode(node.id); + + if (!node.children.empty()) { + ainode->mNumChildren = node.children.size(); + ainode->mChildren = new aiNode*[ainode->mNumChildren]; + + for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { + aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]); + child->mParent = ainode; + ainode->mChildren[i] = child; + } + } + + aiMatrix4x4 matrix = ainode->mTransformation; + if (node.matrix.isPresent) { + CopyValue(node.matrix.value, matrix); + } + else { + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + aiMatrix4x4 t; + aiMatrix4x4::Translation(trans, t); + matrix = t * matrix; + } + + if (node.scale.isPresent) { + aiVector3D scal(1.f); + CopyValue(node.scale.value, scal); + aiMatrix4x4 s; + aiMatrix4x4::Scaling(scal, s); + matrix = s * matrix; + } + + + if (node.rotation.isPresent) { + aiQuaternion rot; + CopyValue(node.rotation.value, rot); + matrix = aiMatrix4x4(rot.GetMatrix()) * matrix; + } + } + + if (!node.meshes.empty()) { + int count = 0; + for (size_t i = 0; i < node.meshes.size(); ++i) { + int idx = node.meshes[i].GetIndex(); + count += meshOffsets[idx + 1] - meshOffsets[idx]; + } + + ainode->mNumMeshes = count; + ainode->mMeshes = new unsigned int[count]; + + int k = 0; + for (size_t i = 0; i < node.meshes.size(); ++i) { + int idx = node.meshes[i].GetIndex(); + for (size_t j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) { + ainode->mMeshes[k] = j; + } + } + } + + if (node.camera) { + pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + } + + if (node.light) { + pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + } + + return ainode; +} + +void glTFImporter::ImportNodes(glTF::Asset& r) +{ + if (!r.scene) return; + + std::vector< Ref > rootNodes = r.scene->nodes; + + // The root nodes + unsigned int numRootNodes = rootNodes.size(); + if (numRootNodes == 1) { // a single root node: use it + mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); + } + else if (numRootNodes > 1) { // more than one root node: create a fake root + aiNode* root = new aiNode("ROOT"); + root->mChildren = new aiNode*[numRootNodes]; + for (unsigned int i = 0; i < numRootNodes; ++i) { + aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); + node->mParent = root; + root->mChildren[root->mNumChildren++] = node; + } + mScene->mRootNode = root; + } + + //if (!mScene->mRootNode) { + // mScene->mRootNode = new aiNode("EMPTY"); + //} +} + +void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r) +{ + embeddedTexIdxs.resize(r.images.Size(), -1); + + int numEmbeddedTexs = 0; + for (size_t i = 0; i < r.images.Size(); ++i) { + if (r.images[i].HasData()) + numEmbeddedTexs += 1; + } + + if (numEmbeddedTexs == 0) + return; + + mScene->mTextures = new aiTexture*[numEmbeddedTexs]; + + // Add the embedded textures + for (size_t i = 0; i < r.images.Size(); ++i) { + Image img = r.images[i]; + if (!img.HasData()) continue; + + int idx = mScene->mNumTextures++; + embeddedTexIdxs[i] = idx; + + aiTexture* tex = mScene->mTextures[idx] = new aiTexture(); + + size_t length = img.GetDataLength(); + void* data = img.StealData(); + + tex->mWidth = static_cast(length); + tex->mHeight = 0; + tex->pcData = reinterpret_cast(data); + + if (!img.mimeType.empty()) { + const char* ext = strchr(img.mimeType.c_str(), '/') + 1; + if (ext) { + if (strcmp(ext, "jpeg") == 0) ext = "jpg"; + + size_t len = strlen(ext); + if (len <= 3) { + strcpy(tex->achFormatHint, ext); + } + } + } + } +} + +void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { + + this->mScene = pScene; + + // read the asset file + glTF::Asset asset(pIOHandler); + asset.Load(pFile, GetExtension(pFile) == "glb"); + + + // + // Copy the data out + // + + ImportEmbeddedTextures(asset); + ImportMaterials(asset); + + ImportMeshes(asset); + + ImportCameras(asset); + ImportLights(asset); + + ImportNodes(asset); + + // TODO: it does not split the loaded vertices, should it? + pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; + + if (pScene->mNumMeshes == 0) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } +} + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + diff --git a/code/glTFImporter.h b/code/glTFImporter.h new file mode 100644 index 000000000..5d06730a5 --- /dev/null +++ b/code/glTFImporter.h @@ -0,0 +1,90 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 AI_GLTFIMPORTER_H_INC +#define AI_GLTFIMPORTER_H_INC + +#include "BaseImporter.h" +#include "DefaultIOSystem.h" + +struct aiNode; + + +namespace glTF +{ + class Asset; +} + +namespace Assimp { + +/** + * Load the glTF format. + * https://github.com/KhronosGroup/glTF/tree/master/specification + */ +class glTFImporter : public BaseImporter{ +public: + glTFImporter(); + virtual ~glTFImporter(); + virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const; + +protected: + virtual const aiImporterDesc* GetInfo() const; + virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ); + +private: + + std::vector meshOffsets; + + std::vector embeddedTexIdxs; + + aiScene* mScene; + + void ImportEmbeddedTextures(glTF::Asset& a); + void ImportMaterials(glTF::Asset& a); + void ImportMeshes(glTF::Asset& a); + void ImportCameras(glTF::Asset& a); + void ImportLights(glTF::Asset& a); + void ImportNodes(glTF::Asset& a); + +}; + +} // Namespace assimp + +#endif // AI_GLTFIMPORTER_H_INC + diff --git a/code/irrXMLWrapper.h b/code/irrXMLWrapper.h index 526a04d1b..29d69864f 100644 --- a/code/irrXMLWrapper.h +++ b/code/irrXMLWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -76,7 +76,7 @@ public: // ---------------------------------------------------------------------------------- //! Construction from an existing IOStream - CIrrXML_IOStreamReader(IOStream* _stream) + explicit CIrrXML_IOStreamReader(IOStream* _stream) : stream (_stream) , t (0) { diff --git a/code/qnan.h b/code/qnan.h index 5c5139490..e8d3ab7e2 100644 --- a/code/qnan.h +++ b/code/qnan.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/contrib/clipper/clipper.cpp b/contrib/clipper/clipper.cpp index b2316ccd5..c8c62bc2a 100644 --- a/contrib/clipper/clipper.cpp +++ b/contrib/clipper/clipper.cpp @@ -26,7 +26,7 @@ * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24–28, 2005 , Long Beach, California, USA * +* September 24–28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ diff --git a/contrib/clipper/clipper.hpp b/contrib/clipper/clipper.hpp index f6f196d0d..3d6510dff 100644 --- a/contrib/clipper/clipper.hpp +++ b/contrib/clipper/clipper.hpp @@ -26,7 +26,7 @@ * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24–28, 2005 , Long Beach, California, USA * +* September 24–28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ diff --git a/contrib/openddlparser/CREDITS b/contrib/openddlparser/CREDITS new file mode 100644 index 000000000..a2b01eb13 --- /dev/null +++ b/contrib/openddlparser/CREDITS @@ -0,0 +1,16 @@ +=============================================================== +OpenDDL-Parser +Developers and Contributors +=============================================================== + +- Kim Kulling ( kimmi ): +Founder + +- Fredrik Hansson ( FredrikHson ): +Improvements value interface, serveral bugfixes. + +- Henry Read ( henrya2 ): +Static build option, Interface improvements + +- Paul Holland ( pkholland ): +Bugfixes. diff --git a/contrib/openddlparser/LICENSE b/contrib/openddlparser/LICENSE new file mode 100644 index 000000000..4c1476bc4 --- /dev/null +++ b/contrib/openddlparser/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Kim Kulling + +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. + diff --git a/contrib/openddlparser/README.md b/contrib/openddlparser/README.md index 195de6932..619747d23 100644 --- a/contrib/openddlparser/README.md +++ b/contrib/openddlparser/README.md @@ -1,29 +1,39 @@ The OpenDDL-Parser ================== -A simple and fast OpenDDL Parser -Current build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser) +The OpenDDL-Parser is a small and easy to use library for OpenDDL-file-format-parsing. OpenDDL is the shortcut for Open Data Description Language, a data-declaration language introduced by Eric Lengyel. Please check http://openddl.org/ if you want to learn more about it. + +Build status +============ +Linux build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser) +Current coverity check status: + + Coverity Scan Build Status + Get the source code =================== -You can get the code from our git repository, which is located at GitHub. You can clone the repository like: +You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command: > git clone https://github.com/kimkulling/openddl-parser.git -Build from repo -=============== -To build the library you need to install cmake first ( see http://www.cmake.org/ for more information ). Make also sure that a compiler toolchain is installed on your machine. -After installing it you can open a console and type: +Building the source from the GitHub-Repo +======================================== +To build the library you need to install cmake first ( see http://www.cmake.org/ for more information ). Make also sure that a compiler tool-chain is installed on your machine. +After installing it you can open a console and enter: > cmake CMakeLists.txt -This command will generate a build environment for your installed build enrironment ( for Visual Studio the project files will be generated, for gcc the makefiles will be generated ). +This command will generate a build environment for your installed build enrironment ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). When using an IDE open the IDE and run the build. When using GNU-make type in your console: > make and that's all. +When using Visual Studio CMake will generate you a solution for ythe library. Just build it there. + Use the library =============== To use the OpenDDL-parser you need to build the lib first. Now add the @@ -88,24 +98,39 @@ int main( int argc, char *argv[] ) { How to access the imported data =============================== -The data is organized as a tree. You can get the root tree with the following code: +The data is organized as a tree. You can get the root-node of the tree with the following code: -``` +```cpp OpenDDLParser theParser; theParser.setBuffer( buffer, size ); const bool result( theParser.parse() ); if ( result ) { DDLNode *root = theParser.getRoot(); - DDLNode::DllNodeList childs = root->getChildNodeList(); for ( size_t i=0; igetProperty(); // to get properties - std:.string type = child->getType(); // to get the node type - Value *values = child->getValue(); // to get the data; + Property *prop = child->getProperty(); // to get properties + std::string type = child->getType(); // to get the node type + Value *values = child->getValue(); // to get the data; + + // to loop through all values + while ( values != ddl_nullptr ) { + int current = values->getInt32(); + values = value->getNext(); + } } } ``` -The instance called root contains the data. +The node instance called root contains the data. + +All data lists are organized as linked lists. + +Reference documentation +======================= +Please check http://kimkulling.github.io/openddl-parser/doxygen_html/index.html. + +Projects using OpenDDL-Parser +============================= +- Asset Importer Lib: https://github.com/assimp/assimp . diff --git a/contrib/openddlparser/code/DDLNode.cpp b/contrib/openddlparser/code/DDLNode.cpp index 5d3fd03f9..0cc95bdfc 100644 --- a/contrib/openddlparser/code/DDLNode.cpp +++ b/contrib/openddlparser/code/DDLNode.cpp @@ -49,11 +49,7 @@ static void releaseReferencedNames( Reference *ref ) { return; } - if( ref->m_referencedName ) { - for( size_t i = 0; i < ref->m_numRefs; i++ ) { - delete ref->m_referencedName; - } - } + delete ref; } DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent ) @@ -121,7 +117,6 @@ const std::string &DDLNode::getType() const { return m_type; } - void DDLNode::setName( const std::string &name ) { m_name = name; } @@ -143,6 +138,10 @@ bool DDLNode::hasProperty( const std::string &name ) { return ( ddl_nullptr != prop ); } +bool DDLNode::hasProperties() const { + return( ddl_nullptr != m_properties ); +} + Property *DDLNode::findPropertyByName( const std::string &name ) { if( name.empty() ) { return ddl_nullptr; @@ -151,9 +150,10 @@ Property *DDLNode::findPropertyByName( const std::string &name ) { if( ddl_nullptr == m_properties ) { return ddl_nullptr; } + Property *current( m_properties ); while( ddl_nullptr != current ) { - int res = strncmp( current->m_key->m_text.m_buffer, name.c_str(), name.size() ); + int res = strncmp( current->m_key->m_buffer, name.c_str(), name.size() ); if( 0 == res ) { return current; } diff --git a/contrib/openddlparser/code/OpenDDLCommon.cpp b/contrib/openddlparser/code/OpenDDLCommon.cpp new file mode 100644 index 000000000..c0a2b0318 --- /dev/null +++ b/contrib/openddlparser/code/OpenDDLCommon.cpp @@ -0,0 +1,179 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +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. +-----------------------------------------------------------------------------------------------*/ +#include +#include + +BEGIN_ODDLPARSER_NS + +Text::Text( const char *buffer, size_t numChars ) +: m_capacity( 0 ) +, m_len( 0 ) +, m_buffer( ddl_nullptr ) { + set( buffer, numChars ); +} + +Text::~Text() { + clear(); +} + +void Text::clear() { + delete[] m_buffer; + m_buffer = ddl_nullptr; + m_capacity = 0; + m_len = 0; +} + +void Text::set( const char *buffer, size_t numChars ) { + clear(); + if( numChars > 0 ) { + m_len = numChars; + m_capacity = m_len + 1; + m_buffer = new char[ m_capacity ]; + strncpy( m_buffer, buffer, numChars ); + m_buffer[ numChars ] = '\0'; + } +} + +bool Text::operator == ( const std::string &name ) const { + if( m_len != name.size() ) { + return false; + } + const int res( strncmp( m_buffer, name.c_str(), name.size() ) ); + + return ( 0 == res ); +} + +bool Text::operator == ( const Text &rhs ) const { + if( m_len != rhs.m_len ) { + return false; + } + + const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) ); + + return ( 0 == res ); +} + +Name::Name( NameType type, Text *id ) +: m_type( type ) +, m_id( id ) { + // empty +} + +Name::~Name() { + delete m_id; + m_id = ddl_nullptr; +} + +Reference::Reference() +: m_numRefs( 0 ) +, m_referencedName( ddl_nullptr ) { + // empty +} + +Reference::Reference( size_t numrefs, Name **names ) +: m_numRefs( numrefs ) +, m_referencedName( ddl_nullptr ) { + if ( numrefs > 0 ) { + m_referencedName = new Name *[ numrefs ]; + for ( size_t i = 0; i < numrefs; i++ ) { + Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id ); + m_referencedName[ i ] = name; + } + } +} + +Reference::~Reference() { + for( size_t i = 0; i < m_numRefs; i++ ) { + delete m_referencedName[ i ]; + } + m_numRefs = 0; + m_referencedName = ddl_nullptr; +} + +size_t Reference::sizeInBytes() { + if ( 0 == m_numRefs ) { + return 0; + } + + size_t size( 0 ); + for ( size_t i = 0; i < m_numRefs; i++ ) { + Name *name( m_referencedName[ i ] ); + if ( ddl_nullptr != name ) { + size += name->m_id->m_len; + } + } + + return size; +} + +Property::Property( Text *id ) +: m_key( id ) +, m_value( ddl_nullptr ) +, m_ref( ddl_nullptr ) +, m_next( ddl_nullptr ) { + // empty +} + +Property::~Property() { + m_key = ddl_nullptr; + m_value = ddl_nullptr; + m_ref = ddl_nullptr;; + m_next = ddl_nullptr;; +} + +DataArrayList::DataArrayList() +: m_numItems( 0 ) +, m_dataList( ddl_nullptr ) +, m_next( ddl_nullptr ) { + // empty +} + +DataArrayList::~DataArrayList() { + // empty +} + +size_t DataArrayList::size() { + size_t result( 0 ); + DataArrayList *n=m_next; + while( n!=ddl_nullptr ) { + result++; + n=n->m_next; + } + return result; +} + +Context::Context() +: m_root( ddl_nullptr ) { + // empty +} + +Context::~Context() { + clear(); +} + +void Context::clear() { + delete m_root; + m_root = ddl_nullptr; +} + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/code/OpenDDLExport.cpp b/contrib/openddlparser/code/OpenDDLExport.cpp new file mode 100644 index 000000000..43e3bcb02 --- /dev/null +++ b/contrib/openddlparser/code/OpenDDLExport.cpp @@ -0,0 +1,435 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +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. +-----------------------------------------------------------------------------------------------*/ +#include +#include +#include +#include + +#include + +BEGIN_ODDLPARSER_NS + +StreamFormatterBase::StreamFormatterBase() { + +} + +StreamFormatterBase::~StreamFormatterBase() { + +} + +std::string StreamFormatterBase::format( const std::string &statement ) { + std::string tmp( statement ); + return tmp; +} + +IOStreamBase::IOStreamBase( StreamFormatterBase *formatter ) +: m_formatter( formatter ) +, m_file( ddl_nullptr ) { + if (ddl_nullptr == m_formatter) { + m_formatter = new StreamFormatterBase; + } +} + +IOStreamBase::~IOStreamBase() { + delete m_formatter; + m_formatter = ddl_nullptr; +} + +bool IOStreamBase::open( const std::string &name ) { + m_file = ::fopen( name.c_str(), "a" ); + if (m_file == ddl_nullptr) { + return false; + } + + return true; +} + +bool IOStreamBase::close() { + if (ddl_nullptr == m_file) { + return false; + } + + ::fclose( m_file ); + m_file = ddl_nullptr; + + return true; +} + +size_t IOStreamBase::write( const std::string &statement ) { + if (ddl_nullptr == m_file) { + return 0; + } + std::string formatStatement = m_formatter->format( statement ); + return ::fwrite( formatStatement.c_str(), sizeof( char ), formatStatement.size(), m_file ); +} + +struct DDLNodeIterator { + const DDLNode::DllNodeList &m_childs; + size_t m_idx; + + DDLNodeIterator( const DDLNode::DllNodeList &childs ) + : m_childs( childs ) + , m_idx( 0 ) { + // empty + } + + ~DDLNodeIterator() { + // empty + } + + bool getNext( DDLNode **node ) { + if( m_childs.size() > (m_idx+1) ) { + m_idx++; + *node = m_childs[ m_idx ]; + return true; + } + + return false; + } + +private: + DDLNodeIterator() ddl_no_copy; + DDLNodeIterator &operator = ( const DDLNodeIterator & ) ddl_no_copy; +}; + +static void writeLineEnd( std::string &statement ) { + statement += "\n"; +} + +OpenDDLExport::OpenDDLExport( IOStreamBase *stream ) +: m_stream( stream ) { + if (ddl_nullptr == m_stream) { + m_stream = new IOStreamBase(); + } +} + +OpenDDLExport::~OpenDDLExport() { + if (ddl_nullptr != m_stream) { + m_stream->close(); + } + delete m_stream; +} + +bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) { + if( ddl_nullptr == ctx ) { + return false; + } + + DDLNode *root( ctx->m_root ); + if ( ddl_nullptr == root ) { + return true; + } + + if (!filename.empty()) { + if (!m_stream->open( filename )) { + return false; + } + } + + const bool retValue( handleNode( root ) ); + + return retValue; +} + +bool OpenDDLExport::handleNode( DDLNode *node ) { + if( ddl_nullptr == node ) { + return true; + } + + const DDLNode::DllNodeList &childs = node->getChildNodeList(); + if( childs.empty() ) { + return true; + } + DDLNode *current( ddl_nullptr ); + DDLNodeIterator it( childs ); + std::string statement; + bool success( true ); + while( it.getNext( ¤t ) ) { + if( ddl_nullptr != current ) { + success |= writeNode( current, statement ); + if( !handleNode( current ) ) { + success = false; + } + } + } + + return success; +} + +bool OpenDDLExport::writeToStream( const std::string &statement ) { + if (ddl_nullptr == m_stream ) { + return false; + } + + if ( !statement.empty()) { + m_stream->write( statement ); + } + + return true; +} + +bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) { + bool success( true ); + writeNodeHeader( node, statement ); + if (node->hasProperties()) { + success |= writeProperties( node, statement ); + } + writeLineEnd( statement ); + + statement = "}"; + DataArrayList *al( node->getDataArrayList() ); + if ( ddl_nullptr != al ) { + writeValueType( al->m_dataList->m_type, al->m_numItems, statement ); + writeValueArray( al, statement ); + } + Value *v( node->getValue() ); + if (ddl_nullptr != v ) { + writeValueType( v->m_type, 1, statement ); + statement = "{"; + writeLineEnd( statement ); + writeValue( v, statement ); + statement = "}"; + writeLineEnd( statement ); + } + statement = "}"; + writeLineEnd( statement ); + + writeToStream( statement ); + + return true; +} + +bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) { + if (ddl_nullptr == node) { + return false; + } + + statement += node->getType(); + const std::string &name( node->getName() ); + if ( !name.empty() ) { + statement += " "; + statement += "$"; + statement += name; + } + + return true; +} + +bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) { + if ( ddl_nullptr == node ) { + return false; + } + + Property *prop( node->getProperties() ); + // if no properties are there, return + if ( ddl_nullptr == prop ) { + return true; + } + + if ( ddl_nullptr != prop ) { + // for instance (attrib = "position", bla=2) + statement += "("; + bool first( true ); + while ( ddl_nullptr != prop ) { + if (!first) { + statement += ", "; + } else { + first = false; + } + statement += std::string( prop->m_key->m_buffer ); + statement += " = "; + writeValue( prop->m_value, statement ); + prop = prop->m_next; + } + + statement += ")"; + } + + return true; +} + +bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) { + if ( Value::ddl_types_max == type) { + return false; + } + + const std::string typeStr( getTypeToken( type ) ); + statement += typeStr; + // if we have an array to write + if ( numItems > 1 ) { + statement += "["; + char buffer[ 256 ]; + ::memset( buffer, '\0', 256 * sizeof( char ) ); + sprintf( buffer, "%d", numItems ); + statement += buffer; + statement += "]"; + } + + return true; +} + +bool OpenDDLExport::writeValue( Value *val, std::string &statement ) { + if (ddl_nullptr == val) { + return false; + } + + switch ( val->m_type ) { + case Value::ddl_bool: + if ( true == val->getBool() ) { + statement += "true"; + } else { + statement += "false"; + } + break; + case Value::ddl_int8: + { + std::stringstream stream; + const int i = static_cast( val->getInt8() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_int16: + { + std::stringstream stream; + char buffer[ 256 ]; + ::memset( buffer, '\0', 256 * sizeof( char ) ); + sprintf( buffer, "%d", val->getInt16() ); + statement += buffer; + } + break; + case Value::ddl_int32: + { + std::stringstream stream; + char buffer[ 256 ]; + ::memset( buffer, '\0', 256 * sizeof( char ) ); + const int i = static_cast< int >( val->getInt32() ); + sprintf( buffer, "%d", i ); + statement += buffer; + } + break; + case Value::ddl_int64: + { + std::stringstream stream; + const int i = static_cast< int >( val->getInt64() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_unsigned_int8: + { + std::stringstream stream; + const int i = static_cast< unsigned int >( val->getUnsignedInt8() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_unsigned_int16: + { + std::stringstream stream; + const int i = static_cast< unsigned int >( val->getUnsignedInt16() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_unsigned_int32: + { + std::stringstream stream; + const int i = static_cast< unsigned int >( val->getUnsignedInt32() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_unsigned_int64: + { + std::stringstream stream; + const int i = static_cast< unsigned int >( val->getUnsignedInt64() ); + stream << i; + statement += stream.str(); + } + break; + case Value::ddl_half: + break; + case Value::ddl_float: + { + std::stringstream stream; + stream << val->getFloat(); + statement += stream.str(); + } + break; + case Value::ddl_double: + break; + case Value::ddl_string: + { + std::stringstream stream; + stream << val->getString(); + statement += "\""; + statement += stream.str(); + statement += "\""; + } + break; + case Value::ddl_ref: + break; + case Value::ddl_none: + case Value::ddl_types_max: + default: + break; + } + + return true; +} + +bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) { + if (ddl_nullptr == al) { + return false; + } + + if (0 == al->m_numItems) { + return true; + } + + DataArrayList *nextDataArrayList = al ; + Value *nextValue( nextDataArrayList->m_dataList ); + while (ddl_nullptr != nextDataArrayList) { + if (ddl_nullptr != nextDataArrayList) { + statement += "{ "; + nextValue = nextDataArrayList->m_dataList; + size_t idx( 0 ); + while (ddl_nullptr != nextValue) { + if (idx > 0) { + statement += ", "; + } + writeValue( nextValue, statement ); + nextValue = nextValue->m_next; + idx++; + } + statement += " }"; + } + nextDataArrayList = nextDataArrayList->m_next; + } + + return true; +} + +END_ODDLPARSER_NS + diff --git a/contrib/openddlparser/code/OpenDDLParser.cpp b/contrib/openddlparser/code/OpenDDLParser.cpp index 77a1c4a25..921f67aa4 100644 --- a/contrib/openddlparser/code/OpenDDLParser.cpp +++ b/contrib/openddlparser/code/OpenDDLParser.cpp @@ -21,6 +21,7 @@ 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. -----------------------------------------------------------------------------------------------*/ #include +#include #include #include @@ -32,21 +33,21 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # include #endif // _WIN32 -#define DEBUG_HEADER_NAME BEGIN_ODDLPARSER_NS -static const char *Version = "0.1.0"; +static const char *Version = "0.3.0"; namespace Grammar { - static const char * const OpenBracketToken = "{"; - static const char * const CloseBracketToken = "}"; - static const char * const OpenPropertyToken = "("; - static const char * const ClosePropertyToken = ")"; - static const char * const BoolTrue = "true"; - static const char * const BoolFalse = "false"; - static const char * const RefToken = "ref"; - static const char * const CommaSeparator = ","; + static const char *OpenBracketToken = "{"; + static const char *CloseBracketToken = "}"; + static const char *OpenPropertyToken = "("; + static const char *ClosePropertyToken = ")"; + static const char *OpenArrayToken = "["; + static const char *CloseArrayToken = "]"; + static const char *BoolTrue = "true"; + static const char *BoolFalse = "false"; + static const char *CommaSeparator = ","; static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = { "bool", @@ -66,28 +67,42 @@ namespace Grammar { }; } // Namespace Grammar +const char *getTypeToken( Value::ValueType type ) { + return Grammar::PrimitiveTypeToken[ type ]; +} static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) { std::stringstream stream; - stream << "Invalid token " << *in << ", " << exp << " expected." << std::endl; + stream << "Invalid token \"" << *in << "\"" << " expected \"" << exp << "\"" << std::endl; + std::string full(in); + std::string part(full.substr(0,50)); + stream << part; callback( ddl_error_msg, stream.str() ); } static bool isIntegerType( Value::ValueType integerType ) { - if( integerType != Value::ddl_int8 && integerType != Value::ddl_int16 && + if( integerType != Value::ddl_int8 && integerType != Value::ddl_int16 && integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) { return false; } + return true; +} + +static bool isUnsignedIntegerType( Value::ValueType integerType ) { + if( integerType != Value::ddl_unsigned_int8 && integerType != Value::ddl_unsigned_int16 && + integerType != Value::ddl_unsigned_int32 && integerType != Value::ddl_unsigned_int64 ) { + return false; + } return true; } -static DDLNode *createDDLNode( Identifier *id, OpenDDLParser *parser ) { +static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) { if( ddl_nullptr == id || ddl_nullptr == parser ) { return ddl_nullptr; } - const std::string type( id->m_text.m_buffer ); + const std::string type( id->m_buffer ); DDLNode *parent( parser->top() ); DDLNode *node = DDLNode::create( type, "", parent ); @@ -120,7 +135,7 @@ OpenDDLParser::OpenDDLParser() // empty } -OpenDDLParser::OpenDDLParser( char *buffer, size_t len ) +OpenDDLParser::OpenDDLParser( const char *buffer, size_t len ) : m_logCallback( &logMessage ) , m_buffer() , m_context( ddl_nullptr ) { @@ -147,7 +162,7 @@ OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const { return m_logCallback; } -void OpenDDLParser::setBuffer( char *buffer, size_t len ) { +void OpenDDLParser::setBuffer( const char *buffer, size_t len ) { clear(); if( 0 == len ) { return; @@ -177,7 +192,7 @@ size_t OpenDDLParser::getBufferSize() const { void OpenDDLParser::clear() { m_buffer.resize( 0 ); - if( m_context ) { + if( ddl_nullptr != m_context ) { m_context->m_root = ddl_nullptr; } @@ -188,7 +203,7 @@ bool OpenDDLParser::parse() { if( m_buffer.empty() ) { return false; } - + normalizeBuffer( m_buffer ); m_context = new Context; @@ -201,11 +216,23 @@ bool OpenDDLParser::parse() { size_t pos( current - &m_buffer[ 0 ] ); while( pos < m_buffer.size() ) { current = parseNextNode( current, end ); + if(current==ddl_nullptr) { + return false; + } pos = current - &m_buffer[ 0 ]; } return true; } +bool OpenDDLParser::exportContext( Context *ctx, const std::string &filename ) { + if( ddl_nullptr == ctx ) { + return false; + } + + OpenDDLExport myExporter; + return myExporter.exportContext( ctx, filename ); +} + char *OpenDDLParser::parseNextNode( char *in, char *end ) { in = parseHeader( in, end ); in = parseStructure( in, end ); @@ -213,52 +240,30 @@ char *OpenDDLParser::parseNextNode( char *in, char *end ) { return in; } +#ifdef DEBUG_HEADER_NAME static void dumpId( Identifier *id ) { if( ddl_nullptr != id ) { - std::cout << id->m_text.m_buffer << std::endl; + if ( ddl_nullptr != id->m_text.m_buffer ) { + std::cout << id->m_text.m_buffer << std::endl; + } } } +#endif char *OpenDDLParser::parseHeader( char *in, char *end ) { if( ddl_nullptr == in || in == end ) { return in; } - Identifier *id( ddl_nullptr ); + Text *id( ddl_nullptr ); in = OpenDDLParser::parseIdentifier( in, end, &id ); -#ifdef DEBUG_HEADER_NAME +#ifdef DEBUG_HEADER_NAME dumpId( id ); #endif // DEBUG_HEADER_NAME in = lookForNextToken( in, end ); - Property *first( ddl_nullptr ); if( ddl_nullptr != id ) { - if( *in == '(' ) { - in++; - Property *prop( ddl_nullptr ), *prev( ddl_nullptr ); - while( *in != ')' && in != end ) { - in = OpenDDLParser::parseProperty( in, end, &prop ); - in = lookForNextToken( in, end ); - - if( *in != ',' && *in != ')' ) { - logInvalidTokenError( in, ")", m_logCallback ); - return in; - } - - if( ddl_nullptr != prop && *in != ',' ) { - if( ddl_nullptr == first ) { - first = prop; - } - if( ddl_nullptr != prev ) { - prev->m_next = prop; - } - prev = prop; - } - } - in++; - } - // store the node DDLNode *node( createDDLNode( id, this ) ); if( ddl_nullptr != node ) { @@ -267,17 +272,44 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) { std::cerr << "nullptr returned by creating DDLNode." << std::endl; } - // set the properties - if( ddl_nullptr != first ) { - node->setProperties( first ); - } - - Name *name( ddl_nullptr ); - in = OpenDDLParser::parseName( in, end, &name ); - if( ddl_nullptr != name ) { - const std::string nodeName( name->m_id->m_text.m_buffer ); + Name *name(ddl_nullptr); + in = OpenDDLParser::parseName(in, end, &name); + if( ddl_nullptr != name && ddl_nullptr != node ) { + const std::string nodeName( name->m_id->m_buffer ); node->setName( nodeName ); } + + Property *first(ddl_nullptr); + in = lookForNextToken(in, end); + if (*in == Grammar::OpenPropertyToken[0]) { + in++; + Property *prop(ddl_nullptr), *prev(ddl_nullptr); + while (*in != Grammar::ClosePropertyToken[0] && in != end) { + in = OpenDDLParser::parseProperty(in, end, &prop); + in = lookForNextToken(in, end); + + if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) { + logInvalidTokenError(in, Grammar::ClosePropertyToken, m_logCallback); + return ddl_nullptr; + } + + if (ddl_nullptr != prop && *in != Grammar::CommaSeparator[0]) { + if (ddl_nullptr == first) { + first = prop; + } + if (ddl_nullptr != prev) { + prev->m_next = prop; + } + prev = prop; + } + } + in++; + } + + // set the properties + if (ddl_nullptr != first && ddl_nullptr != node) { + node->setProperties(first); + } } return in; @@ -294,16 +326,19 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) { // loop over all children ( data and nodes ) do { in = parseStructureBody( in, end, error ); + if(in == ddl_nullptr){ + return ddl_nullptr; + } } while ( *in != '}' ); in++; } else { in++; logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback ); error = true; - return in; + return ddl_nullptr; } in = lookForNextToken( in, end ); - + // pop node from stack after successful parsing if( !error ) { popNode(); @@ -348,17 +383,17 @@ char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) { if( Value::ddl_none != type ) { // parse a primitive data type in = lookForNextToken( in, end ); - if( *in == '{' ) { + if( *in == Grammar::OpenBracketToken[ 0 ] ) { Reference *refs( ddl_nullptr ); DataArrayList *dtArrayList( ddl_nullptr ); Value *values( ddl_nullptr ); if( 1 == arrayLen ) { size_t numRefs( 0 ), numValues( 0 ); - in = parseDataList( in, end, &values, numValues, &refs, numRefs ); + in = parseDataList( in, end, type, &values, numValues, &refs, numRefs ); setNodeValues( top(), values ); setNodeReferences( top(), refs ); } else if( arrayLen > 1 ) { - in = parseDataArrayList( in, end, &dtArrayList ); + in = parseDataArrayList( in, end, type, &dtArrayList ); setNodeDataArrayList( top(), dtArrayList ); } else { std::cerr << "0 for array is invalid." << std::endl; @@ -369,6 +404,7 @@ char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) { in = lookForNextToken( in, end ); if( *in != '}' ) { logInvalidTokenError( in, std::string( Grammar::CloseBracketToken ), m_logCallback ); + return ddl_nullptr; } else { //in++; } @@ -403,7 +439,7 @@ DDLNode *OpenDDLParser::top() { if( m_stack.empty() ) { return ddl_nullptr; } - + DDLNode *top( m_stack.back() ); return top; } @@ -435,10 +471,10 @@ void OpenDDLParser::normalizeBuffer( std::vector &buffer) { newBuffer.push_back( buffer[ readIdx ] ); } else { if( isComment( c, end ) ) { - readIdx++; + ++readIdx; // skip the comment and the rest of the line while( !isEndofLine( buffer[ readIdx ] ) ) { - readIdx++; + ++readIdx; } } } @@ -462,9 +498,9 @@ char *OpenDDLParser::parseName( char *in, char *end, Name **name ) { if( *in == '%' ) { ntype = LocalName; } - + in++; Name *currentName( ddl_nullptr ); - Identifier *id( ddl_nullptr ); + Text *id( ddl_nullptr ); in = parseIdentifier( in, end, &id ); if( id ) { currentName = new Name( ntype, id ); @@ -472,11 +508,11 @@ char *OpenDDLParser::parseName( char *in, char *end, Name **name ) { *name = currentName; } } - + return in; } -char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) { +char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) { *id = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; @@ -484,7 +520,7 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) { // ignore blanks in = lookForNextToken( in, end ); - + // staring with a number is forbidden if( isNumeric( *in ) ) { return in; @@ -493,13 +529,13 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) { // get size of id size_t idLen( 0 ); char *start( in ); - while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != '(' && *in != ')' ) { - in++; - idLen++; + while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] && *in != '$' ) { + ++in; + ++idLen; } - + const size_t len( idLen ); - Identifier *newId = new Identifier( start, len ); + Text *newId = new Text( start, len ); *id = newId; return in; @@ -529,14 +565,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy } bool ok( true ); - if( *in == '[' ) { + if( *in == Grammar::OpenArrayToken[ 0 ] ) { ok = false; in++; char *start( in ); while ( in != end ) { in++; - if( *in == ']' ) { - len = atoi( start ); + if( *in == Grammar::CloseArrayToken[ 0 ] ) { + len = ::atoi( start ); ok = true; in++; break; @@ -562,9 +598,9 @@ char *OpenDDLParser::parseReference( char *in, char *end, std::vector &na if( nextName ) { names.push_back( nextName ); } - while( ',' == *in ) { + while( Grammar::CommaSeparator[ 0 ] == *in ) { in = getNextSeparator( in, end ); - if( ',' == *in ) { + if( Grammar::CommaSeparator[ 0 ] == *in ) { in = parseName( in, end, &nextName ); if( nextName ) { names.push_back( nextName ); @@ -614,7 +650,7 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, return in; } - if( !isIntegerType( integerType ) ) { + if( !(isIntegerType( integerType ) || isUnsignedIntegerType(integerType)) ) { return in; } @@ -625,7 +661,13 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, } if( isNumeric( *start ) ) { - const int value( atoi( start ) ); +#ifdef OPENDDL_NO_USE_CPP11 + const int64 value( atol( start ) ); // maybe not really 64bit as atoll is but exists without c++11 + const uint64 uvalue( strtoul( start,ddl_nullptr,10 ) ); +#else + const int64 value( atoll( start ) ); + const uint64 uvalue( strtoull( start,ddl_nullptr,10 ) ); +#endif *integer = ValueAllocator::allocPrimData( integerType ); switch( integerType ) { case Value::ddl_int8: @@ -640,15 +682,27 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, case Value::ddl_int64: ( *integer )->setInt64( ( int64 ) value ); break; + case Value::ddl_unsigned_int8: + ( *integer )->setUnsignedInt8( (uint8) uvalue ); + break; + case Value::ddl_unsigned_int16: + ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); + break; + case Value::ddl_unsigned_int32: + ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); + break; + case Value::ddl_unsigned_int64: + ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); + break; default: break; } - } + } return in; } -char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating ) { +char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating, Value::ValueType floatType) { *floating = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; @@ -662,6 +716,11 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating // parse the float value bool ok( false ); + if ( isHexLiteral( start, end ) ) { + parseHexaLiteral( start, end, floating ); + return in; + } + if( isNumeric( *start ) ) { ok = true; } else { @@ -673,9 +732,16 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating } if( ok ) { - const float value( ( float ) atof( start ) ); - *floating = ValueAllocator::allocPrimData( Value::ddl_float ); - ( *floating )->setFloat( value ); + if(floatType == Value::ddl_double) + { + const double value( atof( start ) ); + *floating = ValueAllocator::allocPrimData( Value::ddl_double ); + ( *floating )->setDouble( value ); + } else { + const float value( ( float ) atof( start ) ); + *floating = ValueAllocator::allocPrimData( Value::ddl_float ); + ( *floating )->setFloat( value ); + } } return in; @@ -707,7 +773,7 @@ char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData return in; } -static void createPropertyWithData( Identifier *id, Value *primData, Property **prop ) { +static void createPropertyWithData( Text *id, Value *primData, Property **prop ) { if( ddl_nullptr != primData ) { ( *prop ) = new Property( id ); ( *prop )->m_value = primData; @@ -770,7 +836,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { } in = lookForNextToken( in, end ); - Identifier *id( ddl_nullptr ); + Text *id( ddl_nullptr ); in = parseIdentifier( in, end, &id ); if( ddl_nullptr != id ) { in = lookForNextToken( in, end ); @@ -787,7 +853,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { } else if( isStringLiteral( *in ) ) { // string data in = parseStringLiteral( in, end, &primData ); createPropertyWithData( id, primData, prop ); - } else { // reference data + } else { // reference data std::vector names; in = parseReference( in, end, names ); if( !names.empty() ) { @@ -796,13 +862,14 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { ( *prop )->m_ref = ref; } } - } + } } return in; } -char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) { +char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, Value **data, + size_t &numValues, Reference **refs, size_t &numRefs ) { *data = ddl_nullptr; numValues = numRefs = 0; if( ddl_nullptr == in || in == end ) { @@ -816,22 +883,47 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n while( '}' != *in ) { current = ddl_nullptr; in = lookForNextToken( in, end ); - if( isInteger( in, end ) ) { - in = parseIntegerLiteral( in, end, ¤t ); - } else if( isFloat( in, end ) ) { - in = parseFloatingLiteral( in, end, ¤t ); - } else if( isStringLiteral( *in ) ) { - in = parseStringLiteral( in, end, ¤t ); - } else if( isHexLiteral( in, end ) ) { - in = parseHexaLiteral( in, end, ¤t ); - } else { // reference data + if ( Value::ddl_ref == type ) { std::vector names; in = parseReference( in, end, names ); - if( !names.empty() ) { + if ( !names.empty() ) { Reference *ref = new Reference( names.size(), &names[ 0 ] ); *refs = ref; numRefs = names.size(); } + } else if ( Value::ddl_none == type ) { + if (isInteger( in, end )) { + in = parseIntegerLiteral( in, end, ¤t ); + } else if (isFloat( in, end )) { + in = parseFloatingLiteral( in, end, ¤t ); + } else if (isStringLiteral( *in )) { + in = parseStringLiteral( in, end, ¤t ); + } else if (isHexLiteral( in, end )) { + in = parseHexaLiteral( in, end, ¤t ); + } + } else { + switch(type){ + case Value::ddl_int8: + case Value::ddl_int16: + case Value::ddl_int32: + case Value::ddl_int64: + case Value::ddl_unsigned_int8: + case Value::ddl_unsigned_int16: + case Value::ddl_unsigned_int32: + case Value::ddl_unsigned_int64: + in = parseIntegerLiteral( in, end, ¤t, type); + break; + case Value::ddl_half: + case Value::ddl_float: + case Value::ddl_double: + in = parseFloatingLiteral( in, end, ¤t, type); + break; + case Value::ddl_string: + in = parseStringLiteral( in, end, ¤t ); + break; + default: + break; + } } if( ddl_nullptr != current ) { @@ -846,7 +938,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n } in = getNextSeparator( in, end ); - if( ',' != *in && '}' != *in && !isSpace( *in ) ) { + if( ',' != *in && Grammar::CloseBracketToken[ 0 ] != *in && !isSpace( *in ) ) { break; } } @@ -862,10 +954,10 @@ static DataArrayList *createDataArrayList( Value *currentValue, size_t numValues dataList->m_numItems = numValues; return dataList; - } -char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **dataList ) { - *dataList = ddl_nullptr; + +char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType type, DataArrayList **dataArrayList ) { + *dataArrayList = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } @@ -879,11 +971,12 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **da do { size_t numRefs( 0 ), numValues( 0 ); currentValue = ddl_nullptr; - in = parseDataList( in, end, ¤tValue, numValues, &refs, numRefs ); - if( ddl_nullptr != currentValue ) { + + in = parseDataList( in, end, type, ¤tValue, numValues, &refs, numRefs ); + if( ddl_nullptr != currentValue || 0 != numRefs ) { if( ddl_nullptr == prev ) { - *dataList = createDataArrayList( currentValue, numValues ); - prev = *dataList; + *dataArrayList = createDataArrayList( currentValue, numValues ); + prev = *dataArrayList; } else { currentDataList = createDataArrayList( currentValue, numValues ); if( ddl_nullptr != prev ) { diff --git a/contrib/openddlparser/code/Value.cpp b/contrib/openddlparser/code/Value.cpp index 78ae00c92..3e251c508 100644 --- a/contrib/openddlparser/code/Value.cpp +++ b/contrib/openddlparser/code/Value.cpp @@ -27,6 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS +static Value::Iterator end( ddl_nullptr ); + Value::Iterator::Iterator() : m_start( ddl_nullptr ) , m_current( ddl_nullptr ) { @@ -39,6 +41,12 @@ Value::Iterator::Iterator( Value *start ) // empty } +Value::Iterator::Iterator( const Iterator &rhs ) +: m_start( rhs.m_start ) +, m_current( rhs.m_current ) { + // empty +} + Value::Iterator::~Iterator() { // empty } @@ -61,6 +69,38 @@ Value *Value::Iterator::getNext() { return v; } +const Value::Iterator Value::Iterator::operator++( int ) { + if( ddl_nullptr == m_current ) { + return end; + } + + m_current = m_current->getNext(); + Iterator inst( m_current ); + + return inst; +} + +Value::Iterator &Value::Iterator::operator++( ) { + if( ddl_nullptr == m_current ) { + return end; + } + + m_current = m_current->getNext(); + + return *this; +} + +bool Value::Iterator::operator == ( const Iterator &rhs ) const { + return ( m_current == rhs.m_current ); +} + +Value *Value::Iterator::operator->( ) const { + if(ddl_nullptr == m_current ) { + return ddl_nullptr; + } + return m_current; +} + Value::Value( ValueType type ) : m_type( type ) , m_size( 0 ) @@ -80,7 +120,7 @@ void Value::setBool( bool value ) { bool Value::getBool() { assert( ddl_bool == m_type ); - return ( *m_data ) ? true : false; + return ( *m_data == 1 ); } void Value::setInt8( int8 value ) { @@ -100,7 +140,9 @@ void Value::setInt16( int16 value ) { int16 Value::getInt16() { assert( ddl_int16 == m_type ); - return ( int16 ) ( *m_data ); + int16 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setInt32( int32 value ) { @@ -110,16 +152,21 @@ void Value::setInt32( int32 value ) { int32 Value::getInt32() { assert( ddl_int32 == m_type ); - return ( int32 ) ( *m_data ); + int32 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setInt64( int64 value ) { - assert( ddl_int32 == m_type ); + assert( ddl_int64 == m_type ); ::memcpy( m_data, &value, m_size ); } int64 Value::getInt64() { - return ( int64 ) ( *m_data ); + assert( ddl_int64 == m_type ); + int64 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setUnsignedInt8( uint8 value ) { @@ -129,7 +176,9 @@ void Value::setUnsignedInt8( uint8 value ) { uint8 Value::getUnsignedInt8() const { assert( ddl_unsigned_int8 == m_type ); - return ( uint8 ) ( *m_data ); + uint8 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setUnsignedInt16( uint16 value ) { @@ -139,7 +188,9 @@ void Value::setUnsignedInt16( uint16 value ) { uint16 Value::getUnsignedInt16() const { assert( ddl_unsigned_int16 == m_type ); - return ( uint8 ) ( *m_data ); + uint16 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setUnsignedInt32( uint32 value ) { @@ -149,7 +200,9 @@ void Value::setUnsignedInt32( uint32 value ) { uint32 Value::getUnsignedInt32() const { assert( ddl_unsigned_int32 == m_type ); - return ( uint8 ) ( *m_data ); + uint32 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setUnsignedInt64( uint64 value ) { @@ -159,7 +212,9 @@ void Value::setUnsignedInt64( uint64 value ) { uint64 Value::getUnsignedInt64() const { assert( ddl_unsigned_int64 == m_type ); - return ( uint64 ) ( *m_data ); + uint64 i; + ::memcpy( &i, m_data, m_size ); + return i; } void Value::setFloat( float value ) { @@ -185,9 +240,16 @@ void Value::setDouble( double value ) { } double Value::getDouble() const { - double v; - ::memcpy( &v, m_data, m_size ); - return v; + if ( m_type == ddl_double ) { + double v; + ::memcpy( &v, m_data, m_size ); + return ( float ) v; + } + else { + double tmp; + ::memcpy( &tmp, m_data, 4 ); + return ( double ) tmp; + } } void Value::setString( const std::string &str ) { @@ -195,59 +257,88 @@ void Value::setString( const std::string &str ) { ::memcpy( m_data, str.c_str(), str.size() ); m_data[ str.size() ] = '\0'; } + const char *Value::getString() const { + assert( ddl_string == m_type ); return (const char*) m_data; } +void Value::setRef( Reference *ref ) { + assert( ddl_ref == m_type ); + + if ( ddl_nullptr != ref ) { + const size_t sizeInBytes( ref->sizeInBytes() ); + if ( sizeInBytes > 0 ) { + if ( ddl_nullptr != m_data ) { + delete [] m_data; + } + + m_data = new unsigned char[ sizeof( Reference ) ]; + Reference *myRef = ( Reference * ) m_data; + myRef->m_numRefs = ref->m_numRefs; + myRef->m_referencedName = new Name *[ myRef->m_numRefs ]; + for ( size_t i = 0; i < myRef->m_numRefs; i++ ) { + myRef->m_referencedName[ i ] = new Name( ref->m_referencedName[ i ]->m_type, ref->m_referencedName[ i ]->m_id ); + } + } + } +} + +Reference *Value::getRef() const { + assert( ddl_ref == m_type ); + + return (Reference*) m_data; +} + void Value::dump() { switch( m_type ) { - case ddl_none: - std::cout << "None" << std::endl; - break; - case ddl_bool: - std::cout << getBool() << std::endl; - break; - case ddl_int8: - std::cout << getInt8() << std::endl; - break; - case ddl_int16: - std::cout << getInt16() << std::endl; - break; - case ddl_int32: - std::cout << getInt32() << std::endl; - break; - case ddl_int64: - std::cout << getInt64() << std::endl; - break; - case ddl_unsigned_int8: - std::cout << "Not supported" << std::endl; - break; - case ddl_unsigned_int16: - std::cout << "Not supported" << std::endl; - break; - case ddl_unsigned_int32: - std::cout << "Not supported" << std::endl; - break; - case ddl_unsigned_int64: - std::cout << "Not supported" << std::endl; - break; - case ddl_half: - std::cout << "Not supported" << std::endl; - break; - case ddl_float: - std::cout << getFloat() << std::endl; - break; - case ddl_double: - std::cout << getDouble() << std::endl; - break; - case ddl_string: - std::cout << "Not supported" << std::endl; - break; - case ddl_ref: - std::cout << "Not supported" << std::endl; - break; - default: - break; + case ddl_none: + std::cout << "None" << std::endl; + break; + case ddl_bool: + std::cout << getBool() << std::endl; + break; + case ddl_int8: + std::cout << getInt8() << std::endl; + break; + case ddl_int16: + std::cout << getInt16() << std::endl; + break; + case ddl_int32: + std::cout << getInt32() << std::endl; + break; + case ddl_int64: + std::cout << getInt64() << std::endl; + break; + case ddl_unsigned_int8: + std::cout << "Not supported" << std::endl; + break; + case ddl_unsigned_int16: + std::cout << "Not supported" << std::endl; + break; + case ddl_unsigned_int32: + std::cout << "Not supported" << std::endl; + break; + case ddl_unsigned_int64: + std::cout << "Not supported" << std::endl; + break; + case ddl_half: + std::cout << "Not supported" << std::endl; + break; + case ddl_float: + std::cout << getFloat() << std::endl; + break; + case ddl_double: + std::cout << getDouble() << std::endl; + break; + case ddl_string: + std::cout << getString() << std::endl; + break; + case ddl_ref: + std::cout << "Not supported" << std::endl; + break; + default: + break; } } @@ -259,6 +350,16 @@ Value *Value::getNext() const { return m_next; } +size_t Value::size(){ + size_t result=1; + Value *n=m_next; + while( n!=ddl_nullptr) { + result++; + n=n->m_next; + } + return result; +} + Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { if( type == Value::ddl_none || Value::ddl_types_max == type ) { return ddl_nullptr; @@ -271,22 +372,25 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { data->m_size = sizeof( bool ); break; case Value::ddl_int8: - data->m_size = sizeof( char ); + data->m_size = sizeof( int8 ); break; case Value::ddl_int16: - data->m_size = sizeof( short ); + data->m_size = sizeof( int16 ); break; case Value::ddl_int32: - data->m_size = sizeof( int ); + data->m_size = sizeof( int32 ); break; case Value::ddl_int64: data->m_size = sizeof( int64 ); break; case Value::ddl_unsigned_int8: - data->m_size = sizeof( unsigned char ); + data->m_size = sizeof( uint8 ); + break; + case Value::ddl_unsigned_int16: + data->m_size = sizeof( uint16 ); break; case Value::ddl_unsigned_int32: - data->m_size = sizeof( unsigned int ); + data->m_size = sizeof( uint32 ); break; case Value::ddl_unsigned_int64: data->m_size = sizeof( uint64 ); diff --git a/contrib/openddlparser/include/openddlparser/DDLNode.h b/contrib/openddlparser/include/openddlparser/DDLNode.h index 8fce95f53..137135604 100644 --- a/contrib/openddlparser/include/openddlparser/DDLNode.h +++ b/contrib/openddlparser/include/openddlparser/DDLNode.h @@ -101,6 +101,10 @@ public: /// @return true, if a corresponding property is assigned to the node, false if not. bool hasProperty( const std::string &name ); + /// @brief Will return true, if any properties are assigned to the node instance. + /// @return True, if properties are assigned. + bool hasProperties() const; + /// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found. /// @param name [in] The name for the property to look for. /// @return The property or ddl_nullptr if no property was found. @@ -140,8 +144,8 @@ public: private: DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent = ddl_nullptr ); DDLNode(); - DDLNode( const DDLNode & ); - DDLNode &operator = ( const DDLNode & ); + DDLNode( const DDLNode & ) ddl_no_copy; + DDLNode &operator = ( const DDLNode & ) ddl_no_copy; static void releaseNodes(); private: diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h index e5fe77777..ddf36df31 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h @@ -26,12 +26,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include #ifndef _WIN32 # include -#endif +#endif + +#if defined(_MSC_VER) && !defined( OPENDDL_STATIC_LIBARY ) -#ifdef _MSC_VER # define TAG_DLL_EXPORT __declspec(dllexport) # define TAG_DLL_IMPORT __declspec(dllimport ) # ifdef OPENDDLPARSER_BUILD @@ -55,11 +57,18 @@ BEGIN_ODDLPARSER_NS #ifndef OPENDDL_NO_USE_CPP11 // All C++11 constructs # define ddl_nullptr nullptr +# define ddl_override override +# define ddl_final final +# define ddl_no_copy = delete #else - // Fallback for older compilers + // Fall-back for older compilers # define ddl_nullptr NULL +# define ddl_override +# define ddl_final +# define ddl_no_copy #endif // OPENDDL_NO_USE_CPP11 +// Forward declarations class DDLNode; class Value; @@ -69,6 +78,7 @@ struct Reference; struct Property; struct DataArrayList; +// Platform-specific typedefs #ifdef _WIN32 typedef signed __int64 int64_impl; typedef unsigned __int64 uint64_impl; @@ -87,205 +97,149 @@ typedef unsigned short uint16; ///< Unsigned integer, 2 byte typedef unsigned int uint32; ///< Unsigned integer, 4 byte typedef uint64_impl uint64; ///< Unsigned integer, 8 byte +/// @brief Stores a text. +/// +/// A text is stored in a simple character buffer. Texts buffer can be +/// greater than the number of stored characters in them. +struct DLL_ODDLPARSER_EXPORT Text { + size_t m_capacity; ///< The capacity of the text. + size_t m_len; ///< The length of the text. + char *m_buffer; ///< The buffer with the text. + + /// @brief The constructor with a given text buffer. + /// @param buffer [in] The buffer. + /// @param numChars [in] The number of characters in the buffer. + Text( const char *buffer, size_t numChars ); + + /// @brief The destructor. + ~Text(); + + /// @brief Clears the text. + void clear(); + + /// @brief Set a new text. + /// @param buffer [in] The buffer. + /// @param numChars [in] The number of characters in the buffer. + void set( const char *buffer, size_t numChars ); + + /// @brief The compare operator for std::strings. + bool operator == ( const std::string &name ) const; + + /// @brief The compare operator for Texts. + bool operator == ( const Text &rhs ) const; + +private: + Text( const Text & ) ddl_no_copy; + Text &operator = ( const Text & ) ddl_no_copy; +}; + /// @brief Description of the type of a name. enum NameType { GlobalName, ///< Name is global. LocalName ///< Name is local. }; -/// @brief Stores a text -struct Text { - size_t m_capacity; - size_t m_len; - char *m_buffer; - - Text( const char *buffer, size_t numChars ) - : m_capacity( 0 ) - , m_len( 0 ) - , m_buffer( ddl_nullptr ) { - set( buffer, numChars ); - } - - ~Text() { - clear(); - } - - void clear() { - delete[] m_buffer; - m_buffer = ddl_nullptr; - m_capacity = 0; - m_len = 0; - } - - void set( const char *buffer, size_t numChars ) { - clear(); - if( numChars > 0 ) { - m_len = numChars; - m_capacity = m_len + 1; - m_buffer = new char[ m_capacity ]; - strncpy( m_buffer, buffer, numChars ); - m_buffer[ numChars ] = '\0'; - } - } - - bool operator == ( const std::string &name ) const { - if( m_len != name.size() ) { - return false; - } - const int res( strncmp( m_buffer, name.c_str(), name.size() ) ); - - return ( 0 == res ); - } - - bool operator == ( const Text &rhs ) const { - if( m_len != rhs.m_len ) { - return false; - } - - const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) ); - - return ( 0 == res ); - } - -private: - Text( const Text & ); - Text &operator = ( const Text & ); -}; - -/// @brief Stores an OpenDDL-specific identifier type. -struct Identifier { - Text m_text; - - Identifier( char buffer[], size_t len ) - : m_text( buffer, len ) { - // empty - } - - Identifier( char buffer[] ) - : m_text( buffer, strlen( buffer ) ) { - // empty - } - - bool operator == ( const Identifier &rhs ) const { - return m_text == rhs.m_text; - } - -private: - Identifier( const Identifier & ); - Identifier &operator = ( const Identifier & ); -}; - /// @brief Stores an OpenDDL-specific name -struct Name { - NameType m_type; - Identifier *m_id; +struct DLL_ODDLPARSER_EXPORT Name { + NameType m_type; ///< The type of the name ( @see NameType ). + Text *m_id; ///< The id. - Name( NameType type, Identifier *id ) - : m_type( type ) - , m_id( id ) { - // empty - } + /// @brief The constructor with the type and the id. + /// @param type [in] The name type. + /// @param id [in] The id. + Name( NameType type, Text *id ); + + /// @brief The destructor. + ~Name(); private: - Name( const Name & ); - Name &operator = ( const Name& ); + Name( const Name & ) ddl_no_copy; + Name &operator = ( const Name& ) ddl_no_copy; }; /// @brief Stores a bundle of references. -struct Reference { - size_t m_numRefs; - Name **m_referencedName; +struct DLL_ODDLPARSER_EXPORT Reference { + size_t m_numRefs; ///< The number of stored references. + Name **m_referencedName; ///< The reference names. - Reference() - : m_numRefs( 0 ) - , m_referencedName( ddl_nullptr ) { - // empty - } - - Reference( size_t numrefs, Name **names ) - : m_numRefs( numrefs ) - , m_referencedName( ddl_nullptr ) { - m_referencedName = new Name *[ numrefs ]; - for( size_t i = 0; i < numrefs; i++ ) { - Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id ); - m_referencedName[ i ] = name; - } - } + /// @brief The default constructor. + Reference(); - ~Reference() { - for( size_t i = 0; i < m_numRefs; i++ ) { - delete m_referencedName[ i ]; - } - m_numRefs = 0; - m_referencedName = ddl_nullptr; - } + /// @brief The constructor with an array of ref names. + /// @param numrefs [in] The number of ref names. + /// @param names [in] The ref names. + Reference( size_t numrefs, Name **names ); + + /// @brief The destructor. + ~Reference(); + + /// @brief Returns the size in bytes to store one deep reference copy. + /// @return The size on bytes. + size_t sizeInBytes(); private: - Reference( const Reference & ); - Reference &operator = ( const Reference & ); + Reference( const Reference & ) ddl_no_copy; + Reference &operator = ( const Reference & ) ddl_no_copy; }; /// @brief Stores a property list. -struct Property { - Identifier *m_key; - Value *m_value; - Reference *m_ref; - Property *m_next; +struct DLL_ODDLPARSER_EXPORT Property { + Text *m_key; ///< The identifier / key of the property. + Value *m_value; ///< The value assigned to its key / id ( ddl_nullptr if none ). + Reference *m_ref; ///< References assigned to its key / id ( ddl_nullptr if none ). + Property *m_next; ///< The next property ( ddl_nullptr if none ). - Property( Identifier *id ) - : m_key( id ) - , m_value( ddl_nullptr ) - , m_ref( ddl_nullptr ) - , m_next( ddl_nullptr ) { - // empty - } + /// @brief The default constructor. + Property(); - ~Property() { - m_key = ddl_nullptr; - m_value = ddl_nullptr; - m_ref = ddl_nullptr;; - m_next = ddl_nullptr;; - } + /// @brief The constructor for initialization. + /// @param id [in] The identifier + Property( Text *id ); + + /// @brief The destructor. + ~Property(); private: - Property( const Property & ); - Property &operator = ( const Property & ); + Property( const Property & ) ddl_no_copy; + Property &operator = ( const Property & ) ddl_no_copy; }; /// @brief Stores a data array list. -struct DataArrayList { - size_t m_numItems; - Value *m_dataList; - DataArrayList *m_next; +struct DLL_ODDLPARSER_EXPORT DataArrayList { + size_t m_numItems; ///< The number of items in the list. + Value *m_dataList; ///< The data list ( a Value ). + DataArrayList *m_next; ///< The next data array list ( ddl_nullptr if last ). - DataArrayList() - : m_numItems( 0 ) - , m_dataList( ddl_nullptr ) - , m_next( ddl_nullptr ) { - // empty - } + /// @brief The default constructor for initialization. + DataArrayList(); + + /// @brief The destructor. + ~DataArrayList(); + + /// @brief Gets the length of the array + size_t size(); private: - DataArrayList( const DataArrayList & ); - DataArrayList &operator = ( const DataArrayList & ); + DataArrayList( const DataArrayList & ) ddl_no_copy; + DataArrayList &operator = ( const DataArrayList & ) ddl_no_copy; }; /// @brief Stores the context of a parsed OpenDDL declaration. -struct Context { - DDLNode *m_root; +struct DLL_ODDLPARSER_EXPORT Context { + DDLNode *m_root; ///< The root node of the OpenDDL node tree. - Context() - : m_root( ddl_nullptr ) { - // empty - } + /// @brief Constructor for initialization. + Context(); - ~Context() { - m_root = ddl_nullptr; - } + /// @brief Destructor. + ~Context(); + + /// @brief Clears the whole node tree. + void clear(); private: - Context( const Context & ); - Context &operator = ( const Context & ); + Context( const Context & ) ddl_no_copy; + Context &operator = ( const Context & ) ddl_no_copy; }; END_ODDLPARSER_NS diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLExport.h b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h new file mode 100644 index 000000000..8ede537d9 --- /dev/null +++ b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h @@ -0,0 +1,104 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +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. +-----------------------------------------------------------------------------------------------*/ +#pragma once + +#include +#include + +BEGIN_ODDLPARSER_NS + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT StreamFormatterBase { +public: + StreamFormatterBase(); + virtual ~StreamFormatterBase(); + virtual std::string format( const std::string &statement ); +}; + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT IOStreamBase { +public: + IOStreamBase( StreamFormatterBase *formatter = ddl_nullptr ); + virtual ~IOStreamBase(); + virtual bool open( const std::string &anme ); + virtual bool close(); + virtual size_t write( const std::string &statement ); + +private: + StreamFormatterBase *m_formatter; + FILE *m_file; +}; + +//------------------------------------------------------------------------------------------------- +/// +/// @ingroup OpenDDLParser +/// @brief This class represents the OpenDDLExporter. +/// +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT OpenDDLExport { +public: + /// @brief The class constructor + OpenDDLExport( IOStreamBase *stream = ddl_nullptr ); + + /// @brief The class destructor. + ~OpenDDLExport(); + + /// @brief Export the data of a parser context. + /// @param ctx [in] Pointer to the context. + /// @param filename [in] The filename for the export. + /// @return True in case of success, false in case of an error. + bool exportContext( Context *ctx, const std::string &filename ); + + /// @brief Handles a node export. + /// @param node [in] The node to handle with. + /// @return True in case of success, false in case of an error. + bool handleNode( DDLNode *node ); + + /// @brief Writes the statement to the stream. + /// @param statement [in] The content to write. + /// @return True in case of success, false in case of an error. + bool writeToStream( const std::string &statement ); + +protected: + bool writeNode( DDLNode *node, std::string &statement ); + bool writeNodeHeader( DDLNode *node, std::string &statement ); + bool writeProperties( DDLNode *node, std::string &statement ); + bool writeValueType( Value::ValueType type, size_t numItems, std::string &statement ); + bool writeValue( Value *val, std::string &statement ); + bool writeValueArray( DataArrayList *al, std::string &statement ); + +private: + OpenDDLExport( const OpenDDLExport & ) ddl_no_copy; + OpenDDLExport &operator = ( const OpenDDLExport & ) ddl_no_copy; + +private: + IOStreamBase *m_stream; +}; + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h index 607dcf90c..efeab6026 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h @@ -39,6 +39,11 @@ struct Identifier; struct Reference; struct Property; +/// @brief Utility function to search for the next token or the end of the buffer. +/// @param in [in] The start position in the buffer. +/// @param end [in] The end position in the buffer. +/// @return Pointer showing to the next token or the end of the buffer. +/// @detail Will not increase buffer when already a valid buffer was found. template inline T *lookForNextToken( T *in, T *end ) { @@ -48,13 +53,16 @@ T *lookForNextToken( T *in, T *end ) { return in; } +/// @brief Utility function to go for the next token or the end of the buffer. +/// @param in [in] The start position in the buffer. +/// @param end [in] The end position in the buffer. +/// @return Pointer showing to the next token or the end of the buffer. +/// @detail Will increase buffer by a minimum of one. template inline T *getNextToken( T *in, T *end ) { T *tmp( in ); - while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) { - in++; - } + in = lookForNextToken( in, end ); if( tmp == in ) { in++; } @@ -69,22 +77,78 @@ enum LogSeverity { ddl_error_msg ///< Parser errors }; +DLL_ODDLPARSER_EXPORT const char *getTypeToken( Value::ValueType type ); + +//------------------------------------------------------------------------------------------------- +/// @class OpenDDLParser +/// @ingroup OpenDDLParser + +/// +/// @brief This is the main API for the OpenDDL-parser. +/// +/// Use instances of this class to manage the parsing and handling of your parser contexts. +//------------------------------------------------------------------------------------------------- class DLL_ODDLPARSER_EXPORT OpenDDLParser { public: + /// @brief The log callback function pointer. typedef void( *logCallback )( LogSeverity severity, const std::string &msg ); public: + /// @brief The default class constructor. OpenDDLParser(); - OpenDDLParser( char *buffer, size_t len ); + + /// @brief The class constructor. + /// @param buffer [in] The buffer + /// @param len [in] Size of the buffer + OpenDDLParser( const char *buffer, size_t len ); + + /// @brief The class destructor. ~OpenDDLParser(); + + /// @brief Setter for an own log callback function. + /// @param callback [in] The own callback. void setLogCallback( logCallback callback ); + + /// @brief Getter for the log callback. + /// @return The current log callback. logCallback getLogCallback() const; - void setBuffer( char *buffer, size_t len ); + + /// @brief Assigns a new buffer to parse. + /// @param buffer [in] The buffer + /// @param len [in] Size of the buffer + void setBuffer( const char *buffer, size_t len ); + + /// @brief Assigns a new buffer to parse. + /// @param buffer [in] The buffer as a std::vector. void setBuffer( const std::vector &buffer ); + + /// @brief Returns the buffer pointer. + /// @return The buffer pointer. const char *getBuffer() const; + + /// @brief Returns the size of the buffer. + /// @return The buffer size. size_t getBufferSize() const; + + /// @brief Clears all parser data, including buffer and active context. void clear(); + + /// @brief Starts the parsing of the OpenDDL-file. + /// @return True in case of success, false in case of an error. + /// @remark In case of errors check log. bool parse(); + + bool exportContext( Context *ctx, const std::string &filename ); + + /// @brief Returns the root node. + /// @return The root node. + DDLNode *getRoot() const; + + /// @brief Returns the parser context, only available in case of a succeeded parsing. + /// @return Pointer to the active context or ddl_nullptr. + Context *getContext() const; + +public: // parser helpers char *parseNextNode( char *current, char *end ); char *parseHeader( char *in, char *end ); char *parseStructure( char *in, char *end ); @@ -92,28 +156,24 @@ public: void pushNode( DDLNode *node ); DDLNode *popNode(); DDLNode *top(); - DDLNode *getRoot() const; - Context *getContext() const; - -public: // static parser helpers static void normalizeBuffer( std::vector &buffer ); static char *parseName( char *in, char *end, Name **name ); - static char *parseIdentifier( char *in, char *end, Identifier **id ); + static char *parseIdentifier( char *in, char *end, Text **id ); static char *parsePrimitiveDataType( char *in, char *end, Value::ValueType &type, size_t &len ); static char *parseReference( char *in, char *end, std::vector &names ); static char *parseBooleanLiteral( char *in, char *end, Value **boolean ); static char *parseIntegerLiteral( char *in, char *end, Value **integer, Value::ValueType integerType = Value::ddl_int32 ); - static char *parseFloatingLiteral( char *in, char *end, Value **floating ); + static char *parseFloatingLiteral( char *in, char *end, Value **floating, Value::ValueType floatType= Value::ddl_float ); static char *parseStringLiteral( char *in, char *end, Value **stringData ); static char *parseHexaLiteral( char *in, char *end, Value **data ); static char *parseProperty( char *in, char *end, Property **prop ); - static char *parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ); - static char *parseDataArrayList( char *in, char *end, DataArrayList **dataList ); + static char *parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ); + static char *parseDataArrayList( char *in, char *end, Value::ValueType type, DataArrayList **dataList ); static const char *getVersion(); private: - OpenDDLParser( const OpenDDLParser & ); - OpenDDLParser &operator = ( const OpenDDLParser & ); + OpenDDLParser( const OpenDDLParser & ) ddl_no_copy; + OpenDDLParser &operator = ( const OpenDDLParser & ) ddl_no_copy; private: logCallback m_logCallback; diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h index 8572a37ed..880e4c0b3 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h @@ -26,19 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS -template -inline -bool isComment( T *in, T *end ) { - if( *in == '/' ) { - if( in + 1 != end ) { - if( *( in + 1 ) == '/' ) { - return true; - } - } - } - return false; -} - template inline bool isUpperCase( T in ) { @@ -51,8 +38,8 @@ bool isLowerCase( T in ) { return ( in >= 'a' && in <= 'z' ); } -template -inline +template +inline bool isSpace( const T in ) { return ( ' ' == in || '\t' == in ); } @@ -66,7 +53,7 @@ bool isNewLine( const T in ) { template inline bool isSeparator( T in ) { - if( isSpace( in ) || ',' == in || '{' == in || '}' == in || '[' == in ) { + if( isSpace( in ) || ',' == in || '{' == in || '}' == in || '[' == in || '(' == in || ')' == in ) { return true; } return false; @@ -83,7 +70,7 @@ static const unsigned char chartype_table[ 256 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112-127 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // > 127 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // > 127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -97,18 +84,13 @@ static const unsigned char chartype_table[ 256 ] = { template inline bool isNumeric( const T in ) { - return ( in >= '0' && in <= '9' ); - //return ( chartype_table[in] ); - /*if (in >= '0' && in <= '9' ) - return true; - - return false;*/ + return ( chartype_table[ in ] == 1 ); } template inline bool isNotEndOfToken( T *in, T *end ) { - return ( '}' != *in && ',' != *in && !isSpace( *in ) && in != end ); + return ( '}' != *in && ',' != *in && !isSpace( *in ) && ')' != *in && in != end ); } template @@ -238,7 +220,7 @@ int hex2Decimal( char in ) { if( isNumeric( in ) ) { return ( in - 48 ); } - + char hexCodeLower( 'a' ), hexCodeUpper( 'A' ); for( int i = 0; i<16; i++ ) { if( in == hexCodeLower + i || in == hexCodeUpper + i ) { @@ -249,4 +231,24 @@ int hex2Decimal( char in ) { return ErrorHex2Decimal; } +template +inline +bool isComment( T *in, T *end ) { + if ( *in=='/' ) { + if ( in+1!=end ) { + if ( *( in+1 )=='/' ) { + char *drive( ( in+2 ) ); + if ( (isUpperCase( *drive )||isLowerCase( *drive ))&&*( drive+1 )=='/' ) { + return false; + } else { + return true; + } + } + } + } + + return false; +} + END_ODDLPARSER_NS + diff --git a/contrib/openddlparser/include/openddlparser/Value.h b/contrib/openddlparser/include/openddlparser/Value.h index fc8cc1ee1..242ec8781 100644 --- a/contrib/openddlparser/include/openddlparser/Value.h +++ b/contrib/openddlparser/include/openddlparser/Value.h @@ -42,8 +42,8 @@ class DLL_ODDLPARSER_EXPORT Value { public: /// @brief This class implements an iterator through a Value list. - /// - /// When getting a new value you need to know how to iterate through it. The Value::Iterator + /// + /// When getting a new value you need to know how to iterate through it. The Value::Iterator /// will help you here: /// @code /// Value *val = node->getValue(); @@ -61,6 +61,8 @@ public: /// @param start [in] The first value for iteration, Iterator( Value *start ); + Iterator( const Iterator &rhs ); + /// @brief The class destructor. ~Iterator(); @@ -72,12 +74,26 @@ public: /// @return The next value, is ddl_nullptr in case of being the last item. Value *getNext(); + /// @brief The post-increment operator. + const Iterator operator++( int ); + + /// @brief The pre-increment operator. + Iterator &operator++( ); + + /// @brief The compare operator. + /// @param rhs [in] The instance to compare. + /// @return true if equal. + bool operator == ( const Iterator &rhs ) const; + + /// @brief The * operator. + /// @return The instance or ddl_nullptr if end of list is reached. + Value *operator->( ) const; + private: Value *m_start; Value *m_current; private: - Iterator( const Iterator & ); Iterator &operator = ( const Iterator & ); }; @@ -93,53 +109,161 @@ public: ddl_unsigned_int16, ///< Unsigned integer type, 16 bytes ddl_unsigned_int32, ///< Unsigned integer type, 32 bytes ddl_unsigned_int64, ///< Unsigned integer type, 64 bytes - ddl_half, - ddl_float, - ddl_double, - ddl_string, - ddl_ref, - ddl_types_max + ddl_half, ///< Half data type. + ddl_float, ///< float data type + ddl_double, ///< Double data type. + ddl_string, ///< String data type. + ddl_ref, ///< Reference, used to define references to other data definitions. + ddl_types_max ///< Upper limit. }; + /// @brief The class constructor. + /// @param type [in] The value type. Value( ValueType type ); + + /// @brief The class destructor. ~Value(); + + /// @brief Assigns a boolean to the value. + /// @param value [in9 The value. void setBool( bool value ); + + /// @brief Returns the boolean value. + /// @return The boolean value. bool getBool(); + + /// @brief Assigns a int8 to the value. + /// @param value [in] The value. void setInt8( int8 value ); + + /// @brief Returns the int8 value. + /// @return The int8 value. int8 getInt8(); + + /// @brief Assigns a int16 to the value. + /// @param value [in] The value. void setInt16( int16 value ); + + /// @brief Returns the int16 value. + /// @return The int16 value. int16 getInt16(); + + /// @brief Assigns a int32 to the value. + /// @param value [in] The value. void setInt32( int32 value ); + + /// @brief Returns the int16 value. + /// @return The int32 value. int32 getInt32(); + + /// @brief Assigns a int64 to the value. + /// @param value [in] The value. void setInt64( int64 value ); + + /// @brief Returns the int16 value. + /// @return The int64 value. int64 getInt64(); + + /// @brief Assigns a unsigned int8 to the value. + /// @param value [in] The value. void setUnsignedInt8( uint8 value ); + + /// @brief Returns the unsigned int8 value. + /// @return The unsigned int8 value. uint8 getUnsignedInt8() const; + + /// @brief Assigns a unsigned int16 to the value. + /// @param value [in] The value. void setUnsignedInt16( uint16 value ); + + /// @brief Returns the unsigned int16 value. + /// @return The unsigned int16 value. uint16 getUnsignedInt16() const; + + /// @brief Assigns a unsigned int32 to the value. + /// @param value [in] The value. void setUnsignedInt32( uint32 value ); + + /// @brief Returns the unsigned int8 value. + /// @return The unsigned int32 value. uint32 getUnsignedInt32() const; + + /// @brief Assigns a unsigned int64 to the value. + /// @param value [in] The value. void setUnsignedInt64( uint64 value ); + + /// @brief Returns the unsigned int64 value. + /// @return The unsigned int64 value. uint64 getUnsignedInt64() const; + + /// @brief Assigns a float to the value. + /// @param value [in] The value. void setFloat( float value ); + + /// @brief Returns the float value. + /// @return The float value. float getFloat() const; + + /// @brief Assigns a double to the value. + /// @param value [in] The value. void setDouble( double value ); + + /// @brief Returns the double value. + /// @return The double value. double getDouble() const; + + /// @brief Assigns a std::string to the value. + /// @param value [in] The value. void setString( const std::string &str ); + + /// @brief Returns the std::string value. + /// @return The std::string value. const char *getString() const; + + /// @brief Set the reference. + /// @param ref [in] Pointer showing to the reference. + void setRef( Reference *ref ); + + /// @brief Returns the pointer showing to the reference. + /// @return Pointer showing to the reference. + Reference *getRef() const; + + /// @brief Dumps the value. void dump(); + + /// @brief Assigns the next value. + /// @param next [n] The next value. void setNext( Value *next ); + + /// @brief Returns the next value. + /// @return The next value.s Value *getNext() const; + /// @brief Gets the length of the array. + /// @return The number of items in the array. + size_t size(); + ValueType m_type; size_t m_size; unsigned char *m_data; Value *m_next; + +private: + Value &operator =( const Value & ) ddl_no_copy; + Value( const Value & ) ddl_no_copy; }; +///------------------------------------------------------------------------------------------------ +/// @brief This class implements the value allocator. +///------------------------------------------------------------------------------------------------ struct DLL_ODDLPARSER_EXPORT ValueAllocator { static Value *allocPrimData( Value::ValueType type, size_t len = 1 ); static void releasePrimData( Value **data ); + +private: + ValueAllocator() ddl_no_copy; + ValueAllocator( const ValueAllocator & ) ddl_no_copy; + ValueAllocator &operator = ( const ValueAllocator & ) ddl_no_copy; }; END_ODDLPARSER_NS diff --git a/contrib/rapidjson/include/rapidjson/allocators.h b/contrib/rapidjson/include/rapidjson/allocators.h new file mode 100644 index 000000000..24e6044b3 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/allocators.h @@ -0,0 +1,261 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + std::free(originalPtr); + return NULL; + } + return std::realloc(originalPtr, newSize); + } + static void Free(void *ptr) { std::free(ptr); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator { +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + RAPIDJSON_DELETE(ownBaseAllocator_); + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while (chunkHead_ && chunkHead_ != userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); + + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + if (newSize == 0) + return NULL; + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + increment = RAPIDJSON_ALIGN(increment); + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + void* newBuffer = Malloc(newSize); + RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) { (void)ptr; } // Do nothing + +private: + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; + + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + */ + void AddChunk(size_t capacity) { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); + ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity)); + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + } + + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/contrib/rapidjson/include/rapidjson/document.h b/contrib/rapidjson/include/rapidjson/document.h new file mode 100644 index 000000000..7079ef8a2 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/document.h @@ -0,0 +1,2136 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ + +/*! \file document.h */ + +#include "reader.h" +#include "internal/meta.h" +#include "internal/strfunc.h" +#include // placement new + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include // std::iterator, std::random_access_iterator_tag +#endif + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +// Forward declaration. +template +class GenericValue; + +template +class GenericDocument; + +//! Name-value pair in a JSON object value. +/*! + This class was internal to GenericValue. It used to be a inner struct. + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. + https://code.google.com/p/rapidjson/issues/detail?id=64 +*/ +template +struct GenericMember { + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericMemberIterator + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS + +//! (Constant) member iterator for a JSON object value +/*! + \tparam Const Is this a constant iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. + + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. + + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. + + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + */ +template +class GenericMemberIterator + : public std::iterator >::Type> { + + friend class GenericValue; + template friend class GenericMemberIterator; + + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef std::iterator BaseType; + +public: + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstIterator; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstIterator; + + //! Pointer to (const) GenericMember + typedef typename BaseType::pointer Pointer; + //! Reference to (const) GenericMember + typedef typename BaseType::reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef typename BaseType::difference_type DifferenceType; + + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} + + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from + + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) + + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + + //! @name stepping + //@{ + Iterator& operator++(){ ++ptr_; return *this; } + Iterator& operator--(){ --ptr_; return *this; } + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } + //@} + + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} + + //! @name relations + //@{ + bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } + bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } + bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } + bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } + bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } + bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } + //@} + + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} + + //! Distance + DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } + +private: + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + + Pointer ptr_; //!< raw pointer +}; + +#else // RAPIDJSON_NOMEMBERITERATORCLASS + +// class-based member iterator implementation disabled, use plain pointers + +template +struct GenericMemberIterator; + +//! non-const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Iterator; +}; +//! const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; +}; + +#endif // RAPIDJSON_NOMEMBERITERATORCLASS + +/////////////////////////////////////////////////////////////////////////////// +// GenericStringRef + +//! Reference to a constant string (not taking a copy) +/*! + \tparam CharType character type of the string + + This helper class is used to automatically infer constant string + references for string literals, especially from \c const \b (!) + character arrays. + + The main use is for creating JSON string values without copying the + source string via an \ref Allocator. This requires that the referenced + string pointers have a sufficient lifetime, which exceeds the lifetime + of the associated GenericValue. + + \b Example + \code + Value v("foo"); // ok, no need to copy & calculate length + const char foo[] = "foo"; + v.SetString(foo); // ok + + const char* bar = foo; + // Value x(bar); // not ok, can't rely on bar's lifetime + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user + Value y(StringRef(bar, 3)); // ok, explicitly pass length + \endcode + + \see StringRef, GenericValue::SetString +*/ +template +struct GenericStringRef { + typedef CharType Ch; //!< character type of the string + + //! Create string reference from \c const character array + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. + + \tparam N length of the string, automatically inferred + + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ + template + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT + : s(str), length(N-1) {} + + //! Explicitly create string reference from \c const character pointer + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. + + \see StringRef(const CharType*) + + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ + explicit GenericStringRef(const CharType* str) + : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } + + //! Create constant string reference from pointer and length + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator + + \post \ref s == str && \ref length == len + \note Constant complexity. + */ + GenericStringRef(const CharType* str, SizeType len) + : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } + + //! implicit conversion to plain CharType pointer + operator const Ch *() const { return s; } + + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + +private: + //! Disallow copy-assignment + GenericStringRef operator=(const GenericStringRef&); + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; +}; + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + \tparam CharType Character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember +*/ +template +inline GenericStringRef StringRef(const CharType* str) { + return GenericStringRef(str, internal::StrLen(str)); +} + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + This version has better performance with supplied length, and also + supports string containing null characters. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param length The length of source string. + \return GenericStringRef string reference object + \relatesalso GenericStringRef +*/ +template +inline GenericStringRef StringRef(const CharType* str, size_t length) { + return GenericStringRef(str, SizeType(length)); +} + +#if RAPIDJSON_HAS_STDSTRING +//! Mark a string object as constant string +/*! Mark a string object (e.g. \c std::string) as a "string literal". + This function can be used to avoid copying a string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. +*/ +template +inline GenericStringRef StringRef(const std::basic_string& str) { + return GenericStringRef(str.data(), SizeType(str.size())); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue type traits +namespace internal { + +template +struct IsGenericValueImpl : FalseType {}; + +// select candidates according to nested encoding and allocator types +template struct IsGenericValueImpl::Type, typename Void::Type> + : IsBaseOf, T>::Type {}; + +// helper to match arbitrary GenericValue instantiations, including derived classes +template struct IsGenericValue : IsGenericValueImpl::Type {}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue + +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. +/*! + A JSON value can be one of 7 types. This class is a variant type supporting + these types. + + Use the Value if UTF8 and default allocator + + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. +*/ +template > +class GenericValue { +public: + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + typedef GenericValue ValueType; //!< Value type of itself. + + //!@name Constructors and destructor. + //@{ + + //! Default constructor creates a null value. + GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) { + rhs.flags_ = kNullFlag; // give up contents + } +#endif + +private: + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); + + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); +#endif + +public: + + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { + static const unsigned defaultFlags[7] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, + kNumberAnyFlag + }; + RAPIDJSON_ASSERT(type <= kNumberType); + flags_ = defaultFlags[type]; + + // Use ShortString to store empty string. + if (type == kStringType) + data_.ss.SetLength(0); + } + + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \see CopyFrom() + */ + template< typename SourceAllocator > + GenericValue(const GenericValue& rhs, Allocator & allocator); + + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen + template + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT +#else + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT +#endif + : data_(), flags_(b ? kTrueFlag : kFalseFlag) { + // safe-guard against failing SFINAE + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + } + + //! Constructor for int value. + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) { + data_.n.i64 = i; + if (i >= 0) + flags_ |= kUintFlag | kUint64Flag; + } + + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) { + data_.n.u64 = u; + if (!(u & 0x80000000)) + flags_ |= kIntFlag | kInt64Flag; + } + + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) { + data_.n.i64 = i64; + if (i64 >= 0) { + flags_ |= kNumberUint64Flag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + flags_ |= kUintFlag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { + data_.n.u64 = u64; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + flags_ |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + flags_ |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + +#if defined(__APPLE__) + //! Constructor for unsigned long value. + explicit GenericValue(unsigned long u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { + data_.n.u64 = u64; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + flags_ |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + flags_ |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + +#if !defined(__x86_64__) + //! Constructor for size_t value. + explicit GenericValue( size_t u ) RAPIDJSON_NOEXCEPT : data_(), flags_( kNumberUintFlag ) { + data_.n.u64 = u; + if ( !( u&0x80000000 ) ) + flags_ |= kIntFlag|kInt64Flag; + } +#endif +#endif + + //! Constructor for double value. + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); } + + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } +#endif + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(flags_) { + case kArrayFlag: + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(data_.a.elements); + break; + + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(data_.o.members); + break; + + case kCopyStringFlag: + Allocator::Free(const_cast(data_.s.str)); + break; + + default: + break; // Do nothing for other types. + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + RAPIDJSON_ASSERT(this != &rhs); + this->~GenericValue(); + RawAssign(rhs); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { + return *this = rhs.Move(); + } +#endif + + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { + GenericValue s(str); + return *this = s; + } + + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + operator=(T value) { + GenericValue v(value); + return *this = v; + } + + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); + this->~GenericValue(); + new (this) GenericValue(rhs, allocator); + return *this; + } + + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } + //@} + + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + */ + template + bool operator==(const GenericValue& rhs) const { + typedef GenericValue RhsType; + if (GetType() != rhs.GetType()) + return false; + + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; + + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + + case kStringType: + return StringEqual(rhs); + + case kNumberType: + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } + else + return data_.n.u64 == rhs.data_.n.u64; + + default: // kTrueType, kFalseType, kNullType + return true; + } + } + + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + +#if RAPIDJSON_HAS_STDSTRING + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } +#endif + + //! Equal-to operator with primitive types + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + + //! Not-equal-to operator + /*! \return !(*this == rhs) + */ + template + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with const C-string pointer + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(flags_ & kTypeMask); } + bool IsNull() const { return flags_ == kNullFlag; } + bool IsFalse() const { return flags_ == kFalseFlag; } + bool IsTrue() const { return flags_ == kTrueFlag; } + bool IsBool() const { return (flags_ & kBoolFlag) != 0; } + bool IsObject() const { return flags_ == kObjectFlag; } + bool IsArray() const { return flags_ == kArrayFlag; } + bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } + bool IsInt() const { return (flags_ & kIntFlag) != 0; } + bool IsUint() const { return (flags_ & kUintFlag) != 0; } + bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } + bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } + bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } + bool IsString() const { return (flags_ & kStringFlag) != 0; } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the number of members in the object. + SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + + //! Check whether the object is empty. + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam SourceAllocator Allocator of the \c name value + + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). + And it can also handle strings with embedded null characters. + + \note Linear time complexity. + */ + template + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + RAPIDJSON_ASSERT(false); // see above note + static GenericValue NullValue; + return NullValue; + } + } + template + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + +#if RAPIDJSON_HAS_STDSTRING + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } +#endif + + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } + + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + +#if RAPIDJSON_HAS_STDSTRING + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } +#endif + + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + template + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } + + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + template + MemberIterator FindMember(const GenericValue& name) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + +#if RAPIDJSON_HAS_STDSTRING + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(StringRef(name)); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(StringRef(name)); } +#endif + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + + Object& o = data_.o; + if (o.size >= o.capacity) { + if (o.capacity == 0) { + o.capacity = kDefaultObjectCapacity; + o.members = reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))); + } + else { + SizeType oldCapacity = o.capacity; + o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 + o.members = reinterpret_cast(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); + } + } + o.members[o.size].name.RawAssign(name); + o.members[o.size].value.RawAssign(value); + o.size++; + return *this; + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } +#endif + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A string value as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(GenericValue& name, T value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Remove all members in the object. + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void RemoveAllMembers() { + RAPIDJSON_ASSERT(IsObject()); + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } +#endif + + template + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } + else + return false; + } + + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + + MemberIterator last(data_.o.members + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) { + // Move the last one to this place + *m = *last; + } + else { + // Only one left, just destroy + m->~Member(); + } + --data_.o.size; + return m; + } + + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note This function preserves the relative order of the remaining object + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos +1); + } + + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note This function preserves the relative order of the remaining object + members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(first >= MemberBegin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= MemberEnd()); + + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; itr != last; ++itr) + itr->~Member(); + std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); + data_.o.size -= (last - first); + return pos; + } + + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } +#endif + + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } + else + return false; + } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + for (SizeType i = 0; i < data_.a.size; ++i) + data_.a.elements[i].~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \pre IsArray() == true + \param index Zero-based index of element. + \see operator[](T*) + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return data_.a.elements[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } + + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); + data_.a.capacity = newCapacity; + } + return *this; + } + + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); + data_.a.elements[data_.a.size++].RawAssign(value); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { + return PushBack(value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } + + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } + + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + data_.a.elements[--data_.a.size].~GenericValue(); + return *this; + } + + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } + + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(data_.a.size > 0); + RAPIDJSON_ASSERT(data_.a.elements != 0); + RAPIDJSON_ASSERT(first >= Begin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); + data_.a.size -= (last - first); + return pos; + } + + //@} + + //!@name Number + //@{ + + int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } + + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) + } + + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + + //@} + + //!@name String + //@{ + + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); } + + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } +#endif + + //@} + + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch(GetType()) { + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); + + case kObjectType: + if (!handler.StartObject()) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. + if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) + return false; + if (!m->value.Accept(handler)) + return false; + } + return handler.EndObject(data_.o.size); + + case kArrayType: + if (!handler.StartArray()) + return false; + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + if (!v->Accept(handler)) + return false; + return handler.EndArray(data_.a.size); + + case kStringType: + return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); + + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); + if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else if (IsUint64()) return handler.Uint64(data_.n.u64); + else return handler.Double(data_.n.d); + } + } + +private: + template friend class GenericValue; + template friend class GenericDocument; + + enum { + kBoolFlag = 0x100, + kNumberFlag = 0x200, + kIntFlag = 0x400, + kUintFlag = 0x800, + kInt64Flag = 0x1000, + kUint64Flag = 0x2000, + kDoubleFlag = 0x4000, + kStringFlag = 0x100000, + kCopyFlag = 0x200000, + kInlineStrFlag = 0x400000, + + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, + + kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler + }; + + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; + + struct String { + const Ch* str; + SizeType length; + unsigned hashcode; //!< reserved + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars + // (excluding the terminating zero) and store a value to determine the length of the contained + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as + // the string terminator as well. For getting the string length back from that value just use + // "MaxSize - str[LenPos]". + // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode + // inline (for `UTF8`-encoded strings). + struct ShortString { + enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; + Ch str[MaxChars]; + + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } + inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN + struct I { + int i; + char padding[4]; + }i; + struct U { + unsigned u; + char padding2[4]; + }u; +#else + struct I { + char padding[4]; + int i; + }i; + struct U { + char padding2[4]; + unsigned u; + }u; +#endif + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes + + struct Object { + Member* members; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + struct Array { + GenericValue* elements; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + union Data { + String s; + ShortString ss; + Number n; + Object o; + Array a; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + flags_ = kArrayFlag; + if (count) { + data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); + std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + } + else + data_.a.elements = NULL; + data_.a.size = data_.a.capacity = count; + } + + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + flags_ = kObjectFlag; + if (count) { + data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); + std::memcpy(data_.o.members, members, count * sizeof(Member)); + } + else + data_.o.members = NULL; + data_.o.size = data_.o.capacity = count; + } + + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { + flags_ = kConstStringFlag; + data_.s.str = s; + data_.s.length = s.length; + } + + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + Ch* str = NULL; + if(ShortString::Usable(s.length)) { + flags_ = kShortStringFlag; + data_.ss.SetLength(s.length); + str = data_.ss.str; + } else { + flags_ = kCopyStringFlag; + data_.s.length = s.length; + str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); + data_.s.str = str; + } + std::memcpy(str, s, s.length * sizeof(Ch)); + str[s.length] = '\0'; + } + + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + data_ = rhs.data_; + flags_ = rhs.flags_; + rhs.flags_ = kNullFlag; + } + + template + bool StringEqual(const GenericValue& rhs) const { + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); + + const SizeType len1 = GetStringLength(); + const SizeType len2 = rhs.GetStringLength(); + if(len1 != len2) { return false; } + + const Ch* const str1 = GetString(); + const Ch* const str2 = rhs.GetString(); + if(str1 == str2) { return true; } // fast path for constant string + + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); + } + + Data data_; + unsigned flags_; +}; + +//! GenericValue with UTF8 encoding +typedef GenericValue > Value; + +/////////////////////////////////////////////////////////////////////////////// +// GenericDocument + +//! A document for parsing JSON text as DOM. +/*! + \note implements Handler concept + \tparam Encoding Encoding for both parsing and string storage. + \tparam Allocator Allocator for allocating memory for the DOM + \tparam StackAllocator Allocator for allocating memory for stack during parsing. + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. +*/ +template , typename StackAllocator = CrtAllocator> +class GenericDocument : public GenericValue { +public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + + //! Constructor + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + } + + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(std::move(rhs.stack_)), + parseResult_(rhs.parseResult_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + } +#endif + + ~GenericDocument() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + { + // The cast to ValueType is necessary here, because otherwise it would + // attempt to call GenericValue's templated assignment operator. + ValueType::operator=(std::forward(rhs)); + + // Calling the destructor here would prematurely call stack_'s destructor + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = std::move(rhs.stack_); + parseResult_ = rhs.parseResult_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + + return *this; + } +#endif + + //! Exchange the contents of this document with those of another. + /*! + \param other Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //!@name Parse from stream + //!@{ + + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} + + //!@name Parse in-place from mutable string + //!@{ + + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} + + //!@name Parse from read-only string + //!@{ + + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + //!@} + + //!@name Handling parse errors + //!@{ + + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //!@} + + //! Get the allocator of this document. + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } + +private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; + + // callers of the following private Handler functions + template friend class GenericReader; // for parsing + template friend class GenericValue; // for deep copying + + // Implementation of Handler + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + return true; + } + + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } + +private: + //! Prohibit copying + GenericDocument(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); + + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + stack_.ShrinkToFit(); + } + + void Destroy() { + RAPIDJSON_DELETE(ownAllocator_); + } + + static const size_t kDefaultStackCapacity = 1024; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; + ParseResult parseResult_; +}; + +//! GenericDocument with UTF8 encoding +typedef GenericDocument > Document; + +// defined here due to the dependency on GenericDocument +template +template +inline +GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) +{ + switch (rhs.GetType()) { + case kObjectType: + case kArrayType: { // perform deep copy via SAX Handler + GenericDocument d(&allocator); + rhs.Accept(d); + RawAssign(*d.stack_.template Pop(1)); + } + break; + case kStringType: + if (rhs.flags_ == kConstStringFlag) { + flags_ = rhs.flags_; + data_ = *reinterpret_cast(&rhs.data_); + } else { + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + } + break; + default: // kNumberType, kTrueType, kFalseType, kNullType + flags_ = rhs.flags_; + data_ = *reinterpret_cast(&rhs.data_); + break; + } +} + +RAPIDJSON_NAMESPACE_END + +#if defined(_MSC_VER) || defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/contrib/rapidjson/include/rapidjson/encodedstream.h b/contrib/rapidjson/include/rapidjson/encodedstream.h new file mode 100644 index 000000000..fd3bfaf13 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/encodedstream.h @@ -0,0 +1,261 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ + +#include "rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Input byte stream wrapper with a statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. +*/ +template +class EncodedInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedInputStream(InputByteStream& is) : is_(is) { + current_ = Encoding::TakeBOM(is_); + } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); + + InputByteStream& is_; + Ch current_; +}; + +//! Output byte stream wrapper with statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. +*/ +template +class EncodedOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { + if (putBOM) + Encoding::PutBOM(os_); + } + + void Put(Ch c) { Encoding::Put(os_, c); } + void Flush() { os_.Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedOutputStream(const EncodedOutputStream&); + EncodedOutputStream& operator=(const EncodedOutputStream&); + + OutputByteStream& os_; +}; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. +*/ +template +class AutoUTFInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } + + UTFType GetType() const { return type_; } + bool HasBOM() const { return hasBOM_; } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } + size_t Tell() const { return is_->Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFInputStream(const AutoUTFInputStream&); + AutoUTFInputStream& operator=(const AutoUTFInputStream&); + + // Detect encoding type with BOM or RFC 4627 + void DetectType() { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 + + const unsigned char* c = (const unsigned char *)is_->Peek4(); + if (!c) + return; + + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); + hasBOM_ = false; + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } + + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 + + if (!hasBOM_) { + unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) { + case 0x08: type_ = kUTF32BE; break; + case 0x0A: type_ = kUTF16BE; break; + case 0x01: type_ = kUTF32LE; break; + case 0x05: type_ = kUTF16LE; break; + case 0x0F: type_ = kUTF8; break; + default: break; // Use type defined by user. + } + } + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + } + + typedef Ch (*TakeFunc)(InputByteStream& is); + InputByteStream* is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; +}; + +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for writing. + \tparam InputByteStream type of output byte stream to be wrapped. +*/ +template +class AutoUTFOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; + + if (putBOM) + PutBOM(); + } + + UTFType GetType() const { return type_; } + + void Put(Ch c) { putFunc_(*os_, c); } + void Flush() { os_->Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFOutputStream(const AutoUTFOutputStream&); + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); + + void PutBOM() { + typedef void (*PutBOMFunc)(OutputByteStream&); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } + + typedef void (*PutFunc)(OutputByteStream&, Ch); + + OutputByteStream* os_; + UTFType type_; + PutFunc putFunc_; +}; + +#undef RAPIDJSON_ENCODINGS_FUNC + +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/encodings.h b/contrib/rapidjson/include/rapidjson/encodings.h new file mode 100644 index 000000000..90b46ed32 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/encodings.h @@ -0,0 +1,625 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ + +#include "rapidjson.h" + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + + enum { supportUnicode = 1 }; // or 0 if not supporting unicode + + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); + + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); + + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); + + // The following functions are deal with byte streams. + + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); + + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); + + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); + + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept +*/ +template +struct UTF8 { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) +#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + Ch c = is.Take(); + if (!(c & 0x80)) { + *codepoint = (unsigned char)c; + return true; + } + + unsigned char type = GetRange((unsigned char)c); + *codepoint = (0xFF >> type) & (unsigned char)c; + bool result = true; + switch (type) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + template + static bool Validate(InputStream& is, OutputStream& os) { +#define COPY() os.Put(c = is.Take()) +#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + Ch c; + COPY(); + if (!(c & 0x80)) + return true; + + bool result = true; + switch (GetRange((unsigned char)c)) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + static unsigned char GetRange(unsigned char c) { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + Ch c = Take(is); + if ((unsigned char)c != 0xEFu) return c; + c = is.Take(); + if ((unsigned char)c != 0xBBu) return c; + c = is.Take(); + if ((unsigned char)c != 0xBFu) return c; + c = is.Take(); + return c; + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return is.Take(); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. +*/ +template +struct UTF16 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put((v & 0x3FF) | 0xDC00); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) { + *codepoint = c; + return true; + } + else if (c <= 0xDBFF) { + *codepoint = (c & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (c & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + Ch c; + os.Put(c = is.Take()); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } +}; + +//! UTF-16 little endian encoding. +template +struct UTF16LE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned short)c == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take(); + c |= (unsigned char)is.Take() << 8; + return c; + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFFu); os.Put(0xFEu); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(c & 0xFFu); + os.Put((c >> 8) & 0xFFu); + } +}; + +//! UTF-16 big endian encoding. +template +struct UTF16BE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned short)c == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take(); + return c; + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFEu); os.Put(0xFFu); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put((c >> 8) & 0xFFu); + os.Put(c & 0xFFu); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. +*/ +template +struct UTF32 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } +}; + +//! UTF-32 little endian enocoding. +template +struct UTF32LE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take(); + c |= (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take() << 16; + c |= (unsigned char)is.Take() << 24; + return c; + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(c & 0xFFu); + os.Put((c >> 8) & 0xFFu); + os.Put((c >> 16) & 0xFFu); + os.Put((c >> 24) & 0xFFu); + } +}; + +//! UTF-32 big endian encoding. +template +struct UTF32BE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take() << 24; + c |= (unsigned char)is.Take() << 16; + c |= (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take(); + return c; + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put((c >> 24) & 0xFFu); + os.Put((c >> 16) & 0xFFu); + os.Put((c >> 8) & 0xFFu); + os.Put(c & 0xFFu); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ASCII + +//! ASCII encoding. +/*! http://en.wikipedia.org/wiki/ASCII + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept +*/ +template +struct ASCII { + typedef CharType Ch; + + enum { supportUnicode = 0 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + unsigned char c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + unsigned char c = is.Take(); + os.Put(c); + return c <= 0x7F; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + Ch c = Take(is); + return c; + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return is.Take(); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// AutoUTF + +//! Runtime-specified UTF encoding type of a stream. +enum UTFType { + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. +}; + +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). +*/ +template +struct AutoUTF { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + + template + RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } + + template + RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + typedef bool (*DecodeFunc)(InputStream&, unsigned*); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } + + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } + +#undef RAPIDJSON_ENCODINGS_FUNC +}; + +/////////////////////////////////////////////////////////////////////////////// +// Transcoder + +//! Encoding conversion. +template +struct Transcoder { + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } + + //! Validate one Unicode codepoint from an encoded stream. + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } +}; + +//! Specialization of Transcoder with same source and target encoding. +template +struct Transcoder { + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Encoding::Validate(is, os); // source/target encoding are the same + } +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || defined(_MSV_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/contrib/rapidjson/include/rapidjson/error/en.h b/contrib/rapidjson/include/rapidjson/error/en.h new file mode 100644 index 000000000..d5f9caab8 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/error/en.h @@ -0,0 +1,65 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H__ +#define RAPIDJSON_ERROR_EN_H__ + +#include "error.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: + return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ERROR_EN_H__ diff --git a/contrib/rapidjson/include/rapidjson/error/error.h b/contrib/rapidjson/include/rapidjson/error/error.h new file mode 100644 index 000000000..f9094fb95 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/error/error.h @@ -0,0 +1,146 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H__ +#define RAPIDJSON_ERROR_ERROR_H__ + +#include "../rapidjson.h" + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult { + + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } + + //! Conversion to \c bool, returns \c true, iff !\ref IsError(). + operator bool() const { return !IsError(); } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ERROR_ERROR_H__ diff --git a/contrib/rapidjson/include/rapidjson/filereadstream.h b/contrib/rapidjson/include/rapidjson/filereadstream.h new file mode 100644 index 000000000..3913eb74b --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/filereadstream.h @@ -0,0 +1,88 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ + +#include "rapidjson.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN + +//! File byte stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileReadStream { +public: + typedef char Ch; //!< Character type (byte). + + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 <= bufferLast_) ? current_ : 0; + } + +private: + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } + + std::FILE* fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/filewritestream.h b/contrib/rapidjson/include/rapidjson/filewritestream.h new file mode 100644 index 000000000..afd7e19b8 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/filewritestream.h @@ -0,0 +1,95 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "rapidjson.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of C file stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileWriteStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) { + std::memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } + + if (n > 0) { + std::memset(current_, c, n); + current_ += n; + } + } + + void Flush() { + if (current_ != buffer_) { + size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } + current_ = buffer_; + } + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream&); + FileWriteStream& operator=(const FileWriteStream&); + + std::FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream& stream, char c, size_t n) { + stream.PutN(c, n); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/biginteger.h b/contrib/rapidjson/include/rapidjson/internal/biginteger.h new file mode 100644 index 000000000..4477cf5d1 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/biginteger.h @@ -0,0 +1,290 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) +#include // for _umul128 +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class BigInteger { +public: + typedef uint64_t Type; + + BigInteger(const BigInteger& rhs) : count_(rhs.count_) { + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + + explicit BigInteger(uint64_t u) : count_(1) { + digits_[0] = u; + } + + BigInteger(const char* decimals, size_t length) : count_(1) { + RAPIDJSON_ASSERT(length > 0); + digits_[0] = 0; + size_t i = 0; + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 + while (length >= kMaxDigitPerIteration) { + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); + length -= kMaxDigitPerIteration; + i += kMaxDigitPerIteration; + } + + if (length > 0) + AppendDecimal64(decimals + i, decimals + i + length); + } + + BigInteger& operator=(const BigInteger &rhs) + { + if (this != &rhs) { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + + BigInteger& operator=(uint64_t u) { + digits_[0] = u; + count_ = 1; + return *this; + } + + BigInteger& operator+=(uint64_t u) { + Type backup = digits_[0]; + digits_[0] += u; + for (size_t i = 0; i < count_ - 1; i++) { + if (digits_[i] >= backup) + return *this; // no carry + backup = digits_[i + 1]; + digits_[i + 1] += 1; + } + + // Last carry + if (digits_[count_ - 1] < backup) + PushBack(1); + + return *this; + } + + BigInteger& operator*=(uint64_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + uint64_t hi; + digits_[i] = MulAdd64(digits_[i], u, k, &hi); + k = hi; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator*=(uint32_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + const uint64_t c = digits_[i] >> 32; + const uint64_t d = digits_[i] & 0xFFFFFFFF; + const uint64_t uc = u * c; + const uint64_t ud = u * d; + const uint64_t p0 = ud + k; + const uint64_t p1 = uc + (p0 >> 32); + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); + k = p1 >> 32; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator<<=(size_t shift) { + if (IsZero() || shift == 0) return *this; + + size_t offset = shift / kTypeBit; + size_t interShift = shift % kTypeBit; + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + + if (interShift == 0) { + std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + count_ += offset; + } + else { + digits_[count_] = 0; + for (size_t i = count_; i > 0; i--) + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); + digits_[offset] = digits_[0] << interShift; + count_ += offset; + if (digits_[count_]) + count_++; + } + + std::memset(digits_, 0, offset * sizeof(Type)); + + return *this; + } + + bool operator==(const BigInteger& rhs) const { + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; + } + + bool operator==(const Type rhs) const { + return count_ == 1 && digits_[0] == rhs; + } + + BigInteger& MultiplyPow5(unsigned exp) { + static const uint32_t kPow5[12] = { + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + if (exp == 0) return *this; + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 + if (exp > 0) *this *= kPow5[exp - 1]; + return *this; + } + + // Compute absolute difference of this and rhs. + // Assume this != rhs + bool Difference(const BigInteger& rhs, BigInteger* out) const { + int cmp = Compare(rhs); + RAPIDJSON_ASSERT(cmp != 0); + const BigInteger *a, *b; // Makes a > b + bool ret; + if (cmp < 0) { a = &rhs; b = this; ret = true; } + else { a = this; b = &rhs; ret = false; } + + Type borrow = 0; + for (size_t i = 0; i < a->count_; i++) { + Type d = a->digits_[i] - borrow; + if (i < b->count_) + d -= b->digits_[i]; + borrow = (d > a->digits_[i]) ? 1 : 0; + out->digits_[i] = d; + if (d != 0) + out->count_ = i + 1; + } + + return ret; + } + + int Compare(const BigInteger& rhs) const { + if (count_ != rhs.count_) + return count_ < rhs.count_ ? -1 : 1; + + for (size_t i = count_; i-- > 0;) + if (digits_[i] != rhs.digits_[i]) + return digits_[i] < rhs.digits_[i] ? -1 : 1; + + return 0; + } + + size_t GetCount() const { return count_; } + Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } + bool IsZero() const { return count_ == 1 && digits_[0] == 0; } + +private: + void AppendDecimal64(const char* begin, const char* end) { + uint64_t u = ParseUint64(begin, end); + if (IsZero()) + *this = u; + else { + unsigned exp = static_cast(end - begin); + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u + } + } + + void PushBack(Type digit) { + RAPIDJSON_ASSERT(count_ < kCapacity); + digits_[count_++] = digit; + } + + static uint64_t ParseUint64(const char* begin, const char* end) { + uint64_t r = 0; + for (const char* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); + r = r * 10u + (unsigned)(*p - '0'); + } + return r; + } + + // Assume a * b + k < 2^128 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t low = _umul128(a, b, outHigh) + k; + if (low < k) + (*outHigh)++; + return low; +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(a) * static_cast(b); + p += k; + *outHigh = static_cast(p >> 64); + return static_cast(p); +#else + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; + x1 += (x0 >> 32); // can't give carry + x1 += x2; + if (x1 < x2) + x3 += (static_cast(1) << 32); + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); + uint64_t hi = x3 + (x1 >> 32); + + lo += k; + if (lo < k) + hi++; + *outHigh = hi; + return lo; +#endif + } + + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 + static const size_t kCapacity = kBitCount / sizeof(Type); + static const size_t kTypeBit = sizeof(Type) * 8; + + Type digits_[kCapacity]; + size_t count_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/diyfp.h b/contrib/rapidjson/include/rapidjson/internal/diyfp.h new file mode 100644 index 000000000..7a55ee31c --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/diyfp.h @@ -0,0 +1,248 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) +#include +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +struct DiyFp { + DiyFp() {} + + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp& rhs) const { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp& rhs) const { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = static_cast(p >> 64); + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) && __GNUC__ >= 4 + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & (static_cast(1) << 63))) { + res.f <<= 1; + res.e--; + } + return res; +#endif + } + + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + double ToDouble() const { + union { + double d; + uint64_t u64; + }u; + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); + return u.d; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPowerByIndex(size_t index) { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline DiyFp GetCachedPower(int e, int* K) { + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} + +inline DiyFp GetCachedPower10(int exp, int *outExp) { + unsigned index = (static_cast(exp) + 348u) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); + } + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DIYFP_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/dtoa.h b/contrib/rapidjson/include/rapidjson/internal/dtoa.h new file mode 100644 index 000000000..d04ae21cc --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/dtoa.h @@ -0,0 +1,217 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ + +#include "itoa.h" // GetDigitsLut() +#include "diyfp.h" +#include "ieee754.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline unsigned CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} + +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast(kappa)]); + return; + } + } +} + +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; +} + +inline char* Prettify(char* buffer, int length, int k) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (length <= kk && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + return &buffer[length + offset]; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } +} + +inline char* dtoa(double value, char* buffer) { + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K); + } +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DTOA_ diff --git a/contrib/rapidjson/include/rapidjson/internal/ieee754.h b/contrib/rapidjson/include/rapidjson/internal/ieee754.h new file mode 100644 index 000000000..2fdaf54b3 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/ieee754.h @@ -0,0 +1,77 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class Double { +public: + Double() {} + Double(double d) : d_(d) {} + Double(uint64_t u) : u_(u) {} + + double Value() const { return d_; } + uint64_t Uint64Value() const { return u_; } + + double NextPositiveDouble() const { + RAPIDJSON_ASSERT(!Sign()); + return Double(u_ + 1).Value(); + } + + bool Sign() const { return (u_ & kSignMask) != 0; } + uint64_t Significand() const { return u_ & kSignificandMask; } + int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } + + bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } + bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } + + uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } + int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } + uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } + + static unsigned EffectiveSignificandSize(int order) { + if (order >= -1021) + return 53; + else if (order <= -1074) + return 0; + else + return (unsigned)order + 1074; + } + +private: + static const int kSignificandSize = 52; + static const int kExponentBias = 0x3FF; + static const int kDenormalExponent = 1 - kExponentBias; + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + union { + double d_; + uint64_t u_; + }; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_IEEE754_ diff --git a/contrib/rapidjson/include/rapidjson/internal/itoa.h b/contrib/rapidjson/include/rapidjson/internal/itoa.h new file mode 100644 index 000000000..01a4e7e72 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/itoa.h @@ -0,0 +1,304 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline const char* GetDigitsLut() { + static const char cDigitsLut[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' + }; + return cDigitsLut; +} + +inline char* u32toa(uint32_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + + if (value < 10000) { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[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++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[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++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = static_cast('0' + static_cast(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++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; +} + +inline char* i32toa(int32_t value, char* buffer) { + uint32_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u32toa(u, buffer); +} + +inline char* u64toa(uint64_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + const uint64_t kTen8 = 100000000; + const uint64_t kTen9 = kTen8 * 10; + const uint64_t kTen10 = kTen8 * 100; + const uint64_t kTen11 = kTen8 * 1000; + const uint64_t kTen12 = kTen8 * 10000; + const uint64_t kTen13 = kTen8 * 100000; + const uint64_t kTen14 = kTen8 * 1000000; + const uint64_t kTen15 = kTen8 * 10000000; + const uint64_t kTen16 = kTen8 * kTen8; + + if (value < kTen8) { + uint32_t v = static_cast(value); + if (v < 10000) { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[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++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < kTen16) { + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + 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 >= kTen15) + *buffer++ = cDigitsLut[d1]; + if (value >= kTen14) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= kTen13) + *buffer++ = cDigitsLut[d2]; + if (value >= kTen12) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= kTen11) + *buffer++ = cDigitsLut[d3]; + if (value >= kTen10) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= kTen9) + *buffer++ = cDigitsLut[d4]; + if (value >= kTen8) + *buffer++ = cDigitsLut[d4 + 1]; + + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else { + const uint32_t a = static_cast(value / kTen16); // 1 to 1844 + value %= kTen16; + + if (a < 10) + *buffer++ = static_cast('0' + static_cast(a)); + else if (a < 100) { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) { + *buffer++ = static_cast('0' + static_cast(a / 100)); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + 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++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; +} + +inline char* i64toa(int64_t value, char* buffer) { + uint64_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u64toa(u, buffer); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ITOA_ diff --git a/contrib/rapidjson/include/rapidjson/internal/meta.h b/contrib/rapidjson/include/rapidjson/internal/meta.h new file mode 100644 index 000000000..5a9aaa428 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/meta.h @@ -0,0 +1,181 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +#include "../rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif +#if defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching +template struct Void { typedef void Type; }; + +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// +template struct BoolType { + static const bool Value = Cond; + typedef BoolType Type; +}; +typedef BoolType TrueType; +typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + +template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; +template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; +template struct SelectIfCond : SelectIfImpl::template Apply {}; +template struct SelectIf : SelectIfCond {}; + +template struct AndExprCond : FalseType {}; +template <> struct AndExprCond : TrueType {}; +template struct OrExprCond : TrueType {}; +template <> struct OrExprCond : FalseType {}; + +template struct BoolExpr : SelectIf::Type {}; +template struct NotExpr : SelectIf::Type {}; +template struct AndExpr : AndExprCond::Type {}; +template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst +template struct AddConst { typedef const T Type; }; +template struct MaybeAddConst : SelectIfCond {}; +template struct RemoveConst { typedef T Type; }; +template struct RemoveConst { typedef T Type; }; + + +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// +template struct IsSame : FalseType {}; +template struct IsSame : TrueType {}; + +template struct IsConst : FalseType {}; +template struct IsConst : TrueType {}; + +template +struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + +template struct IsPointer : FalseType {}; +template struct IsPointer : TrueType {}; + +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#if RAPIDJSON_HAS_CXX11_TYPETRAITS + +template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + +template struct IsBaseOfImpl { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + static Yes Check(const D*, T); + static No Check(const B*, int); + + struct Host { + operator const B*() const; + operator const D*(); + }; + + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; +}; + +template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// +template struct EnableIfCond { typedef T Type; }; +template struct EnableIfCond { /* empty */ }; + +template struct DisableIfCond { typedef T Type; }; +template struct DisableIfCond { /* empty */ }; + +template +struct EnableIf : EnableIfCond {}; + +template +struct DisableIf : DisableIfCond {}; + +// SFINAE helpers +struct SfinaeTag {}; +template struct RemoveSfinaeTag; +template struct RemoveSfinaeTag { typedef T Type; }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL + +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type + +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type + +} // namespace internal +RAPIDJSON_NAMESPACE_END +//@endcond + +#if defined(__GNUC__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/pow10.h b/contrib/rapidjson/include/rapidjson/internal/pow10.h new file mode 100644 index 000000000..02f475d70 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/pow10.h @@ -0,0 +1,55 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Computes integer powers of 10 in double (10.0^n). +/*! This function uses lookup table for fast and accurate results. + \param n non-negative exponent. Must <= 308. + \return 10.0^n +*/ +inline double Pow10(int n) { + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POW10_ diff --git a/contrib/rapidjson/include/rapidjson/internal/stack.h b/contrib/rapidjson/include/rapidjson/internal/stack.h new file mode 100644 index 000000000..344785dcd --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/stack.h @@ -0,0 +1,196 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +#include "../rapidjson.h" +#include "swap.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. +/*! \tparam Allocator Allocator for allocating stack memory. +*/ +template +class Stack { +public: + // Optimization note: Do not allocate memory for stack_ in constructor. + // Do it lazily when first Push() -> Expand() -> Resize(). + Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { + RAPIDJSON_ASSERT(stackCapacity > 0); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack(Stack&& rhs) + : allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(rhs.stack_), + stackTop_(rhs.stackTop_), + stackEnd_(rhs.stackEnd_), + initialCapacity_(rhs.initialCapacity_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } +#endif + + ~Stack() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack& operator=(Stack&& rhs) { + if (&rhs != this) + { + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = rhs.stack_; + stackTop_ = rhs.stackTop_; + stackEnd_ = rhs.stackEnd_; + initialCapacity_ = rhs.initialCapacity_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } + return *this; + } +#endif + + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + + void Clear() { stackTop_ = stack_; } + + void ShrinkToFit() { + if (Empty()) { + // If the stack is empty, completely deallocate the memory. + Allocator::Free(stack_); + stack_ = 0; + stackTop_ = 0; + stackEnd_ = 0; + } + else + Resize(GetSize()); + } + + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + // Expand the stack if needed + if (stackTop_ + sizeof(T) * count >= stackEnd_) + Expand(count); + + T* ret = reinterpret_cast(stackTop_); + stackTop_ += sizeof(T) * count; + return ret; + } + + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stackTop_ -= count * sizeof(T); + return reinterpret_cast(stackTop_); + } + + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* Bottom() { return (T*)stack_; } + + bool HasAllocator() const { + return allocator_ != 0; + } + + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + bool Empty() const { return stackTop_ == stack_; } + size_t GetSize() const { return static_cast(stackTop_ - stack_); } + size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } + +private: + template + void Expand(size_t count) { + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. + size_t newCapacity; + if (stack_ == 0) { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + newCapacity = initialCapacity_; + } else { + newCapacity = GetCapacity(); + newCapacity += (newCapacity + 1) / 2; + } + size_t newSize = GetSize() + sizeof(T) * count; + if (newCapacity < newSize) + newCapacity = newSize; + + Resize(newCapacity); + } + + void Resize(size_t newCapacity) { + const size_t size = GetSize(); // Backup the current size + stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); + stackTop_ = stack_ + size; + stackEnd_ = stack_ + newCapacity; + } + + void Destroy() { + Allocator::Free(stack_); + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + } + + // Prohibit copy constructor & assignment operator. + Stack(const Stack&); + Stack& operator=(const Stack&); + + Allocator* allocator_; + Allocator* ownAllocator_; + char *stack_; + char *stackTop_; + char *stackEnd_; + size_t initialCapacity_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STACK_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/strfunc.h b/contrib/rapidjson/include/rapidjson/internal/strfunc.h new file mode 100644 index 000000000..84405065a --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/strfunc.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/strtod.h b/contrib/rapidjson/include/rapidjson/internal/strtod.h new file mode 100644 index 000000000..a1b821197 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/strtod.h @@ -0,0 +1,270 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "../rapidjson.h" +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline double FastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double StrtodNormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; +} + +template +inline T Min3(T a, T b, T c) { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); +} + +inline bool StrtodFast(double d, int p, double* result) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 + *result = FastPath(d, p); + return true; + } + else + return false; +} + +// Compute an approximation and see if it is within 1/2 ULP +inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { + uint64_t significand = 0; + size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < length; i++) { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + break; + significand = significand * 10u + static_cast(decimals[i] - '0'); + } + + if (i < length && decimals[i] >= '5') // Rounding + significand++; + + size_t remaining = length - i; + const unsigned kUlpShift = 3; + const unsigned kUlp = 1 << kUlpShift; + int error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + const int dExp = (int)decimalPosition - (int)i + exp; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) { + static const DiyFp kPow10[] = { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp - 1; + RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); + v = v * kPow10[adjustment]; + if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + unsigned precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) { + unsigned scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + static_cast(kUlp); + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); +} + +inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { + const BigInteger dInt(decimals, length); + const int dExp = (int)decimalPosition - (int)length + exp; + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); +} + +inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result; + if (StrtodFast(d, p, &result)) + return result; + + // Trim leading zeros + while (*decimals == '0' && length > 1) { + length--; + decimals++; + decimalPosition--; + } + + // Trim trailing zeros + while (decimals[length - 1] == '0' && length > 1) { + length--; + decimalPosition--; + exp++; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 780; + if ((int)length > kMaxDecimalDigit) { + int delta = (int(length) - kMaxDecimalDigit); + exp += delta; + decimalPosition -= static_cast(delta); + length = kMaxDecimalDigit; + } + + // If too small, underflow to zero + if (int(length) + exp < -324) + return 0.0; + + if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, length, decimalPosition, exp); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/contrib/rapidjson/include/rapidjson/internal/swap.h b/contrib/rapidjson/include/rapidjson/internal/swap.h new file mode 100644 index 000000000..0590921f1 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/swap.h @@ -0,0 +1,37 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom swap() to avoid dependency on C++ header +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). +*/ +template +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { + T tmp = a; + a = b; + b = tmp; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/contrib/rapidjson/include/rapidjson/memorybuffer.h b/contrib/rapidjson/include/rapidjson/memorybuffer.h new file mode 100644 index 000000000..2484b2185 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/memorybuffer.h @@ -0,0 +1,70 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ + +#include "rapidjson.h" +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output byte stream. +/*! + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +struct GenericMemoryBuffer { + typedef char Ch; // byte + + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { stack_.ShrinkToFit(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetBuffer() const { + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericMemoryBuffer<> MemoryBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { + std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/contrib/rapidjson/include/rapidjson/memorystream.h b/contrib/rapidjson/include/rapidjson/memorystream.h new file mode 100644 index 000000000..99feae5d7 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/memorystream.h @@ -0,0 +1,61 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory input byte stream. +/*! + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept +*/ +struct MemoryStream { + typedef char Ch; // byte + + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + + Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } + Ch Take() { return (src_ == end_) ? '\0' : *src_++; } + size_t Tell() const { return static_cast(src_ - begin_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return Tell() + 4 <= size_ ? src_ : 0; + } + + const Ch* src_; //!< Current read position. + const Ch* begin_; //!< Original head of the string. + const Ch* end_; //!< End of stream. + size_t size_; //!< Size of the stream. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h b/contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h new file mode 100644 index 000000000..18111286b --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h @@ -0,0 +1,316 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// 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. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// miloyip: VC supports inttypes.h since VC2013 +#if _MSC_VER >= 1800 +#include +#else + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + +#endif // _MSC_VER >= 1800 + +#endif // _MSC_INTTYPES_H_ ] diff --git a/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h b/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h new file mode 100644 index 000000000..a26fff4bf --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h @@ -0,0 +1,300 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// 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. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. +#if _MSC_VER >= 1600 // [ +#include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#else // ] _MSC_VER >= 1700 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/contrib/rapidjson/include/rapidjson/pointer.h b/contrib/rapidjson/include/rapidjson/pointer.h new file mode 100644 index 000000000..5d2aa8d63 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/pointer.h @@ -0,0 +1,1313 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ + +#include "document.h" +#include "internal/itoa.h" + +RAPIDJSON_NAMESPACE_BEGIN + +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericPointer + +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. +/*! + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" + (https://tools.ietf.org/html/rfc6901). + + A JSON pointer is for identifying a specific value in a JSON document + (GenericDocument). It can simplify coding of DOM tree manipulation, because it + can access multiple-level depth of DOM tree with single API call. + + After it parses a string representation (e.g. "/foo/0" or URI fragment + representation (e.g. "#/foo/0") into its internal representation (tokens), + it can be used to resolve a specific value in multiple documents, or sub-tree + of documents. + + Contrary to GenericValue, Pointer can be copy constructed and copy assigned. + Apart from assignment, a Pointer cannot be modified after construction. + + Although Pointer is very convenient, please aware that constructing Pointer + involves parsing and dynamic memory allocation. A special constructor with user- + supplied tokens eliminates these. + + GenericPointer depends on GenericDocument and GenericValue. + + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > + \tparam Allocator The allocator type for allocating memory for internal representation. + + \note GenericPointer uses same encoding of ValueType. + However, Allocator of GenericPointer is independent of Allocator of Value. +*/ +template +class GenericPointer { +public: + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value + typedef typename EncodingType::Ch Ch; //!< Character type from Value + + //! A token is the basic units of internal representation. + /*! + A JSON pointer string representation "/foo/123" is parsed to two tokens: + "foo" and 123. 123 will be represented in both numeric form and string form. + They are resolved according to the actual value type (object or array). + + For token that are not numbers, or the numeric value is out of bound + (greater than limits of SizeType), they are only treated as string form + (i.e. the token's index will be equal to kPointerInvalidIndex). + + This struct is public so that user can create a Pointer without parsing and + allocation, using a special constructor. + */ + struct Token { + const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. + SizeType length; //!< Length of the name. + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. + }; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor. + GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A null-terminated, string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + */ + explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, internal::StrLen(source)); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source.c_str(), source.size()); + } +#endif + + //! Constructor that parses a string or URI fragment representation, with length of the source string. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param length Length of source. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Slightly faster than the overload without length. + */ + GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, length); + } + + //! Constructor with user-supplied tokens. + /*! + This constructor let user supplies const array of tokens. + This prevents the parsing process and eliminates allocation. + This is preferred for memory constrained environments. + + \param tokens An constant array of tokens representing the JSON pointer. + \param tokenCount Number of tokens. + + \b Example + \code + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } + #define INDEX(i) { #i, sizeof(#i) - 1, i } + + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); + // Equivalent to static const Pointer p("/foo/123"); + + #undef NAME + #undef INDEX + \endcode + */ + GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Destructor. + ~GenericPointer() { + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. + Allocator::Free(tokens_); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator. + GenericPointer& operator=(const GenericPointer& rhs) { + if (this != &rhs) { + // Do not delete ownAllcator + if (nameBuffer_) + Allocator::Free(tokens_); + + tokenCount_ = rhs.tokenCount_; + parseErrorOffset_ = rhs.parseErrorOffset_; + parseErrorCode_ = rhs.parseErrorCode_; + + if (rhs.nameBuffer_) + CopyFromRaw(rhs); // Normally parsed tokens. + else { + tokens_ = rhs.tokens_; // User supplied const tokens. + nameBuffer_ = 0; + } + } + return *this; + } + + //@} + + //!@name Append token + //@{ + + //! Append a token and return a new Pointer + /*! + \param token Token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Token& token, Allocator* allocator = 0) const { + GenericPointer r; + r.allocator_ = allocator; + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); + r.tokens_[tokenCount_].name = p; + r.tokens_[tokenCount_].length = token.length; + r.tokens_[tokenCount_].index = token.index; + return r; + } + + //! Append a name token with length, and return a new Pointer + /*! + \param name Name to be appended. + \param length Length of name. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { + Token token = { name, length, kPointerInvalidIndex }; + return Append(token, allocator); + } + + //! Append a name token without length, and return a new Pointer + /*! + \param name Name (const Ch*) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + Append(T* name, Allocator* allocator = 0) const { + return Append(name, StrLen(name), allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Append a name token, and return a new Pointer + /*! + \param name Name to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { + return Append(name.c_str(), static_cast(name.size()), allocator); + } +#endif + + //! Append a index token, and return a new Pointer + /*! + \param index Index to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(SizeType index, Allocator* allocator = 0) const { + char buffer[21]; + SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer; + buffer[length] = '\0'; + + if (sizeof(Ch) == 1) { + Token token = { (Ch*)buffer, length, index }; + return Append(token, allocator); + } + else { + Ch name[21]; + for (size_t i = 0; i <= length; i++) + name[i] = buffer[i]; + Token token = { name, length, index }; + return Append(token, allocator); + } + } + + //! Append a token by value, and return a new Pointer + /*! + \param value Value (either Uint or String) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { + if (token.IsString()) + return Append(token.GetString(), token.GetStringLength(), allocator); + else { + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + return Append(static_cast(token.GetUint64()), allocator); + } + } + + //!@name Handling Parse Error + //@{ + + //! Check whether this is a valid pointer. + bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } + + //! Get the parsing error offset in code unit. + size_t GetParseErrorOffset() const { return parseErrorOffset_; } + + //! Get the parsing error code. + PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } + + //@} + + //!@name Tokens + //@{ + + //! Get the token array (const version only). + const Token* GetTokens() const { return tokens_; } + + //! Get the number of tokens. + size_t GetTokenCount() const { return tokenCount_; } + + //@} + + //!@name Equality/inequality operators + //@{ + + //! Equality operator. + /*! + \note When any pointers are invalid, always returns false. + */ + bool operator==(const GenericPointer& rhs) const { + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) + return false; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index || + tokens_[i].length != rhs.tokens_[i].length || + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) + { + return false; + } + } + + return true; + } + + //! Inequality operator. + /*! + \note When any pointers are invalid, always returns true. + */ + bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + + //@} + + //!@name Stringify + //@{ + + //! Stringify the pointer into string representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + return Stringify(os); + } + + //! Stringify the pointer into URI fragment representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool StringifyUriFragment(OutputStream& os) const { + return Stringify(os); + } + + //@} + + //!@name Create value + //@{ + + //! Create a value in a subtree. + /*! + If the value is not exist, it creates all parent values and a JSON Null value. + So it always succeed and return the newly created or existing value. + + Remind that it may change types of parents according to tokens, so it + potentially removes previously stored values. For example, if a document + was an array, and "/foo" is used to create a value, then the document + will be changed to an object, and all existing array elements are lost. + + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created (a JSON Null value), or already exists value. + */ + ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + bool exist = true; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) { + v->PushBack(Value().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else { + if (t->index == kPointerInvalidIndex) { // must be object name + if (!v->IsObject()) + v->SetObject(); // Change to Object + } + else { // object name or array index + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + + if (v->IsArray()) { + if (t->index >= v->Size()) { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(Value().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) { + v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator); + v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + exist = false; + } + else + v = &m->value; + } + } + } + + if (alreadyExist) + *alreadyExist = exist; + + return *v; + } + + //! Creates a value in a document. + /*! + \param document A document to be resolved. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created, or already exists value. + */ + template + ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { + return Create(document, document.GetAllocator(), alreadyExist); + } + + //@} + + //!@name Query value + //@{ + + //! Query a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + ValueType* Get(ValueType& root) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + return 0; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return 0; + v = &((*v)[t->index]); + break; + default: + return 0; + } + } + return v; + } + + //! Query a const value in a const subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + const ValueType* Get(const ValueType& root) const { return Get(const_cast(root)); } + + //@} + + //!@name Query a value with default + //@{ + + //! Query a value in a subtree with default value. + /*! + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. + So that this function always succeed. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param defaultValue Default value to be cloned if the value was not exists. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); + } + + //! Query a value in a subtree with default null-terminated string. + ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a subtree with default std::basic_string. + ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } +#endif + + //! Query a value in a subtree with default primitive value. + /*! + \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); + } + + //! Query a value in a document with default value. + template + ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //! Query a value in a document with default null-terminated string. + template + ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a document with default std::basic_string. + template + ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } +#endif + + //! Query a value in a document with default primitive value. + /*! + \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(GenericDocument& document, T defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //@} + + //!@name Set a value + //@{ + + //! Set a value in a subtree, with move semantics. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be set. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = value; + } + + //! Set a value in a subtree, with copy semantics. + ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).CopyFrom(value, allocator); + } + + //! Set a null-terminated string in a subtree. + ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Set a std::basic_string in a subtree. + ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } +#endif + + //! Set a primitive value in a subtree. + /*! + \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value).Move(); + } + + //! Set a value in a document, with move semantics. + template + ValueType& Set(GenericDocument& document, ValueType& value) const { + return Create(document) = value; + } + + //! Set a value in a document, with copy semantics. + template + ValueType& Set(GenericDocument& document, const ValueType& value) const { + return Create(document).CopyFrom(value, document.GetAllocator()); + } + + //! Set a null-terminated string in a document. + template + ValueType& Set(GenericDocument& document, const Ch* value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Sets a std::basic_string in a document. + template + ValueType& Set(GenericDocument& document, const std::basic_string& value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } +#endif + + //! Set a primitive value in a document. + /*! + \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(GenericDocument& document, T value) const { + return Create(document) = value; + } + + //@} + + //!@name Swap a value + //@{ + + //! Swap a value with a value in a subtree. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be swapped. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).Swap(value); + } + + //! Swap a value with a value in a document. + template + ValueType& Swap(GenericDocument& document, ValueType& value) const { + return Create(document).Swap(value); + } + + //@} + + //! Erase a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Whether the resolved value is found and erased. + + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. + */ + bool Erase(ValueType& root) const { + RAPIDJSON_ASSERT(IsValid()); + if (tokenCount_ == 0) // Cannot erase the root + return false; + + ValueType* v = &root; + const Token* last = tokens_ + (tokenCount_ - 1); + for (const Token *t = tokens_; t != last; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + return false; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return false; + v = &((*v)[t->index]); + break; + default: + return false; + } + } + + switch (v->GetType()) { + case kObjectType: + return v->EraseMember(GenericStringRef(last->name, last->length)); + case kArrayType: + if (last->index == kPointerInvalidIndex || last->index >= v->Size()) + return false; + v->Erase(v->Begin() + last->index); + return true; + default: + return false; + } + } + +private: + //! Clone the content from rhs to this. + /*! + \param rhs Source pointer. + \param extraToken Extra tokens to be allocated. + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. + \return Start of non-occupied name buffer, for storing extra names. + */ + Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { + if (!allocator_) // allocator is independently owned. + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) + nameBufferSize += t->length; + + tokenCount_ = rhs.tokenCount_ + extraToken; + tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); + nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + + // Adjust pointers to name buffer + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) + t->name += diff; + + return nameBuffer_ + nameBufferSize; + } + + //! Check whether a character should be percent-encoded. + /*! + According to RFC 3986 2.3 Unreserved Characters. + \param c The character (code unit) to be tested. + */ + bool NeedPercentEncode(Ch c) const { + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); + } + + //! Parse a JSON String or its URI fragment representation into tokens. + /*! + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. + \param length Length of the source string. + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. + */ + void Parse(const Ch* source, size_t length) { + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); + + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + + // Count number of '/' as tokenCount + tokenCount_ = 0; + for (const Ch* s = source; s != source + length; s++) + if (*s == '/') + tokenCount_++; + + Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); + Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + size_t i = 0; + + // Detect if it is a URI fragment + bool uriFragment = false; + if (source[i] == '#') { + uriFragment = true; + i++; + } + + if (i != length && source[i] != '/') { + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; + goto error; + } + + while (i < length) { + RAPIDJSON_ASSERT(source[i] == '/'); + i++; // consumes '/' + + token->name = name; + bool isNumber = true; + + while (i < length && source[i] != '/') { + Ch c = source[i]; + if (uriFragment) { + // Decoding percent-encoding for URI fragment + if (c == '%') { + PercentDecodeStream is(&source[i], source + length); + GenericInsituStringStream os(name); + Ch* begin = os.PutBegin(); + if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; + goto error; + } + size_t len = os.PutEnd(begin); + i += is.Tell() - 1; + if (len == 1) + c = *name; + else { + name += len; + isNumber = false; + i++; + continue; + } + } + else if (NeedPercentEncode(c)) { + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; + goto error; + } + } + + i++; + + // Escaping "~0" -> '~', "~1" -> '/' + if (c == '~') { + if (i < length) { + c = source[i]; + if (c == '0') c = '~'; + else if (c == '1') c = '/'; + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + i++; + } + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + } + + // First check for index: all of characters are digit + if (c < '0' || c > '9') + isNumber = false; + + *name++ = c; + } + token->length = name - token->name; + if (token->length == 0) + isNumber = false; + *name++ = '\0'; // Null terminator + + // Second check for index: more than one digit cannot have leading zero + if (isNumber && token->length > 1 && token->name[0] == '0') + isNumber = false; + + // String to SizeType conversion + SizeType n = 0; + if (isNumber) { + for (size_t j = 0; j < token->length; j++) { + SizeType m = n * 10 + static_cast(token->name[j] - '0'); + if (m < n) { // overflow detection + isNumber = false; + break; + } + n = m; + } + } + + token->index = isNumber ? n : kPointerInvalidIndex; + token++; + } + + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + parseErrorCode_ = kPointerParseErrorNone; + return; + + error: + Allocator::Free(tokens_); + nameBuffer_ = 0; + tokens_ = 0; + tokenCount_ = 0; + parseErrorOffset_ = i; + return; + } + + //! Stringify to string or URI fragment representation. + /*! + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. + \tparam OutputStream type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + RAPIDJSON_ASSERT(IsValid()); + + if (uriFragment) + os.Put('#'); + + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + os.Put('/'); + for (size_t j = 0; j < t->length; j++) { + Ch c = t->name[j]; + if (c == '~') { + os.Put('~'); + os.Put('0'); + } + else if (c == '/') { + os.Put('~'); + os.Put('1'); + } + else if (uriFragment && NeedPercentEncode(c)) { + // Transcode to UTF8 sequence + GenericStringStream source(&t->name[j]); + PercentEncodeStream target(os); + if (!Transcoder >().Validate(source, target)) + return false; + j += source.Tell() - 1; + } + else + os.Put(c); + } + } + return true; + } + + //! A helper stream for decoding a percent-encoded sequence into code unit. + /*! + This stream decodes %XY triplet into code unit (0-255). + If it encounters invalid characters, it sets output code unit as 0 and + mark invalid, and to be checked by IsValid(). + */ + class PercentDecodeStream { + public: + //! Constructor + /*! + \param source Start of the stream + \param end Past-the-end of the stream. + */ + PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} + + Ch Take() { + if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet + valid_ = false; + return 0; + } + src_++; + Ch c = 0; + for (int j = 0; j < 2; j++) { + c <<= 4; + Ch h = *src_; + if (h >= '0' && h <= '9') c += h - '0'; + else if (h >= 'A' && h <= 'F') c += h - 'A' + 10; + else if (h >= 'a' && h <= 'f') c += h - 'a' + 10; + else { + valid_ = false; + return 0; + } + src_++; + } + return c; + } + + size_t Tell() const { return src_ - head_; } + bool IsValid() const { return valid_; } + + private: + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. + const Ch* end_; //!< Past-the-end position. + bool valid_; //!< Whether the parsing is valid. + }; + + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. + template + class PercentEncodeStream { + public: + PercentEncodeStream(OutputStream& os) : os_(os) {} + void Put(char c) { // UTF-8 must be byte + unsigned char u = static_cast(c); + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + os_.Put('%'); + os_.Put(hexDigits[u >> 4]); + os_.Put(hexDigits[u & 15]); + } + private: + OutputStream& os_; + }; + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Pointer. + Ch* nameBuffer_; //!< A buffer containing all names in tokens. + Token* tokens_; //!< A list of tokens. + size_t tokenCount_; //!< Number of tokens in tokens_. + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. + PointerParseErrorCode parseErrorCode_; //!< Parsing error code. +}; + +//! GenericPointer for Value (UTF-8, default allocator). +typedef GenericPointer Pointer; + +//!@name Helper functions for GenericPointer +//@{ + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { + return pointer.Create(root, a); +} + +template +typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Create(root, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { + return pointer.Create(document); +} + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Create(document); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer) { + return pointer.Get(root); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer) { + return pointer.Get(root); +} + +template +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { + return GenericPointer(source, N - 1).Get(root); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Get(root); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { + return pointer.Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { + return pointer.Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { + return GenericPointer(source, N - 1).Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Swap(root, value, a); +} + +template +typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Swap(root, value, a); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Swap(document, value); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Swap(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +bool EraseValueByPointer(T& root, const GenericPointer& pointer) { + return pointer.Erase(root); +} + +template +bool EraseValueByPointer(T& root, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Erase(root); +} + +//@} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POINTER_H_ diff --git a/contrib/rapidjson/include/rapidjson/prettywriter.h b/contrib/rapidjson/include/rapidjson/prettywriter.h new file mode 100644 index 000000000..416dd492e --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/prettywriter.h @@ -0,0 +1,207 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of ouptut os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> +class PrettyWriter : public Writer { +public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + PrettyPrefix(kStringType); + return Base::WriteString(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndObject(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } + + bool StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } + + bool EndArray(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndArray(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} +protected: + void PrettyPrefix(Type type) { + (void)type; + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); + + if (level->inArray) { + if (level->valueCount > 0) { + Base::os_->Put(','); // add comma if it is not the first element in array + Base::os_->Put('\n'); + } + else + Base::os_->Put('\n'); + WriteIndent(); + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } + + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, indentChar_, count); + } + + Ch indentChar_; + unsigned indentCharCount_; + +private: + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter&); + PrettyWriter& operator=(const PrettyWriter&); +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/rapidjson/include/rapidjson/rapidjson.h b/contrib/rapidjson/include/rapidjson/rapidjson.h new file mode 100644 index 000000000..b83f8e22f --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/rapidjson.h @@ -0,0 +1,654 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +/*!\file rapidjson.h + \brief common definitions and configuration + + \see RAPIDJSON_CONFIG + */ + +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration + \brief Configuration macros for library features + + Some RapidJSON features are configurable to adapt the library to a wide + variety of platforms, environments and usage scenarios. Most of the + features can be configured in terms of overriden or predefined + preprocessor macros at compile-time. + + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. + + \note These macros should be given on the compiler command-line + (where applicable) to avoid inconsistent values when compiling + different translation units of a single application. + */ + +#include // malloc(), realloc(), free(), size_t +#include // memset(), memcpy(), memmove(), memcmp() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 0 +#define RAPIDJSON_PATCH_VERSION 2 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NAMESPACE_(BEGIN|END) +/*! \def RAPIDJSON_NAMESPACE + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace + + In order to avoid symbol clashes and/or "One Definition Rule" errors + between multiple inclusions of (different versions of) RapidJSON in + a single binary, users can customize the name of the main RapidJSON + namespace. + + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref + RAPIDJSON_NAMESPACE_END need to be defined as well: + + \code + // in some .cpp file + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } + #include "rapidjson/..." + \endcode + + \see rapidjson + */ +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (opening expression) + \see RAPIDJSON_NAMESPACE +*/ +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (closing expression) + \see RAPIDJSON_NAMESPACE +*/ +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson +#endif +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { +#endif +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +/*! \def RAPIDJSON_NO_INT64DEFINE + \ingroup RAPIDJSON_CONFIG + \brief Use external 64-bit integer types. + + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types + to be available at global scope. + + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to + prevent RapidJSON from defining its own types. +*/ +#ifndef RAPIDJSON_NO_INT64DEFINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#ifdef _MSC_VER +#include "msinttypes/stdint.h" +#include "msinttypes/inttypes.h" +#else +// Other compilers should have this. +#include +#include +#endif +//!@endcond +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_FORCEINLINE + +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && !defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#else +#define RAPIDJSON_FORCEINLINE +#endif +//!@endcond +#endif // RAPIDJSON_FORCEINLINE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! + \def RAPIDJSON_ENDIAN + \ingroup RAPIDJSON_CONFIG + + GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. + + Default detection implemented with reference to + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp +*/ +#ifndef RAPIDJSON_ENDIAN +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(RAPIDJSON_DOXYGEN_RUNNING) +# define RAPIDJSON_ENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_64BIT + +//! Whether using 64-bit architecture +#ifndef RAPIDJSON_64BIT +#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__) +#define RAPIDJSON_64BIT 1 +#else +#define RAPIDJSON_64BIT 0 +#endif +#endif // RAPIDJSON_64BIT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ALIGN + +//! Data alignment of the machine. +/*! \ingroup RAPIDJSON_CONFIG + \param x pointer to align + + Some machines require strict data alignment. Currently the default uses 4 bytes + alignment. User can customize by defining the RAPIDJSON_ALIGN function macro. +*/ +#ifndef RAPIDJSON_ALIGN +#if RAPIDJSON_64BIT == 1 +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) +#else +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_UINT64_C2 + +//! Construct a 64-bit literal by a pair of 32-bit integer. +/*! + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. +*/ +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD + +/*! \def RAPIDJSON_SIMD + \ingroup RAPIDJSON_CONFIG + \brief Enable SSE2/SSE4.2 optimization. + + RapidJSON supports optimized implementations for some parsing operations + based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible + processors. + + To enable these optimizations, two different symbols can be defined; + \code + // Enable SSE2 optimization. + #define RAPIDJSON_SSE2 + + // Enable SSE4.2 optimization. + #define RAPIDJSON_SSE42 + \endcode + + \c RAPIDJSON_SSE42 takes precedence, if both are defined. + + If any of these symbols is defined, RapidJSON defines the macro + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. +*/ +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE + \ingroup RAPIDJSON_CONFIG + \brief User-provided \c SizeType definition. + + In order to avoid using 32-bit size types for indexing strings and arrays, + define this preprocessor symbol and provide the type rapidjson::SizeType + before including RapidJSON: + \code + #define RAPIDJSON_NO_SIZETYPEDEFINE + namespace rapidjson { typedef ::std::size_t SizeType; } + #include "rapidjson/..." + \endcode + + \see rapidjson::SizeType +*/ +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE +#endif +RAPIDJSON_NAMESPACE_BEGIN +//! Size type (for string lengths, array sizes, etc.) +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, + instead of using \c size_t. Users may override the SizeType by defining + \ref RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +RAPIDJSON_NAMESPACE_END +#endif + +// always import std::size_t to rapidjson namespace +RAPIDJSON_NAMESPACE_BEGIN +using std::size_t; +RAPIDJSON_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! \ingroup RAPIDJSON_CONFIG + By default, rapidjson uses C \c assert() for internal assertions. + User can override it by defining RAPIDJSON_ASSERT(x) macro. + + \note Parsing errors are handled and can be customized by the + \ref RAPIDJSON_ERRORS APIs. +*/ +#ifndef RAPIDJSON_ASSERT +#include +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_STATIC_ASSERT + +// Adopt from boost +#ifndef RAPIDJSON_STATIC_ASSERT +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +RAPIDJSON_NAMESPACE_BEGIN +template struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END + +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y + +#if defined(__GNUC__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif +//!@endcond + +/*! \def RAPIDJSON_STATIC_ASSERT + \brief (Internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer + */ +#define RAPIDJSON_STATIC_ASSERT(x) \ + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Helpers + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ +} while((void)0, 0) + +// adopted from Boost +#define RAPIDJSON_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF + +#if defined(__GNUC__) +#define RAPIDJSON_GNUC \ + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#endif + +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) + +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) +#define RAPIDJSON_DIAG_OFF(x) \ + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + +// push/pop support in Clang and GCC>=4.6 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) +#else // GCC >= 4.2, < 4.6 +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ +#endif + +#elif defined(_MSC_VER) + +// pragma (MSVC specific) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) + +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) + +#else + +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ + +#endif // RAPIDJSON_DIAG_* + +/////////////////////////////////////////////////////////////////////////////// +// C++11 features + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) + +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) +// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#else +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#endif +#endif +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept +#else +#define RAPIDJSON_NOEXCEPT /* noexcept */ +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT + +// no automatic detection, yet +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#endif + +//!@endcond + +/////////////////////////////////////////////////////////////////////////////// +// new/delete + +#ifndef RAPIDJSON_NEW +///! customization point for global \c new +#define RAPIDJSON_NEW(x) new x +#endif +#ifndef RAPIDJSON_DELETE +///! customization point for global \c delete +#define RAPIDJSON_DELETE(x) delete x +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allocators and Encodings + +#include "allocators.h" +#include "encodings.h" + +/*! \namespace rapidjson + \brief main RapidJSON namespace + \see RAPIDJSON_NAMESPACE +*/ +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + for (size_t i = 0; i < n; i++) + stream.Put(c); +} + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } + + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +/////////////////////////////////////////////////////////////////////////////// +// Type + +//! Type of JSON value +enum Type { + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/rapidjson/include/rapidjson/reader.h b/contrib/rapidjson/include/rapidjson/reader.h new file mode 100644 index 000000000..6fb29e908 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/reader.h @@ -0,0 +1,1510 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +/*! \file reader.h */ + +#include "rapidjson.h" +#include "encodings.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strtod.h" + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (HasParseError()) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) +//!@endcond + +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN + \ingroup RAPIDJSON_ERRORS + \brief Macro to indicate a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + This macros can be used as a customization point for the internal + error handling mechanism of RapidJSON. + + A common usage model is to throw an exception instead of requiring the + caller to explicitly check the \ref rapidjson::GenericReader::Parse's + return value: + + \code + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + throw ParseException(parseErrorCode, #parseErrorCode, offset) + + #include // std::runtime_error + #include "rapidjson/error/error.h" // rapidjson::ParseResult + + struct ParseException : std::runtime_error, rapidjson::ParseResult { + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) + : std::runtime_error(msg), ParseResult(code, offset) {} + }; + + #include "rapidjson/reader.h" + \endcode + + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + */ +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + SetParseError(parseErrorCode, offset); \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +/*! \def RAPIDJSON_PARSE_ERROR + \ingroup RAPIDJSON_ERRORS + \brief (Internal) macro to indicate and handle a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + + \see RAPIDJSON_PARSE_ERROR_NORETURN + \hideinitializer + */ +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +#include "error/error.h" // ParseErrorCode, ParseResult + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kParseDefaultFlags definition. + + User can define this as any \c ParseFlag combinations. +*/ +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#endif + +//! Combination of parseFlags +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream + */ +enum ParseFlag { + kParseNoFlags = 0, //!< No flags are set. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. +\code +concept Handler { + typename Ch; + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \note implements Handler concept +*/ +template, typename Derived = void> +struct BaseReaderHandler { + typedef typename Encoding::Ch Ch; + + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + + bool Default() { return true; } + bool Null() { return static_cast(*this).Default(); } + bool Bool(bool) { return static_cast(*this).Default(); } + bool Int(int) { return static_cast(*this).Default(); } + bool Uint(unsigned) { return static_cast(*this).Default(); } + bool Int64(int64_t) { return static_cast(*this).Default(); } + bool Uint64(uint64_t) { return static_cast(*this).Default(); } + bool Double(double) { return static_cast(*this).Default(); } + bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } + bool StartObject() { return static_cast(*this).Default(); } + bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool EndObject(SizeType) { return static_cast(*this).Default(); } + bool StartArray() { return static_cast(*this).Default(); } + bool EndArray(SizeType) { return static_cast(*this).Default(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamLocalCopy + +namespace internal { + +template::copyOptimization> +class StreamLocalCopy; + +//! Do copy optimization. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original), original_(original) {} + ~StreamLocalCopy() { original_ = s; } + + Stream s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + + Stream& original_; +}; + +//! Keep reference. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original) {} + + Stream& s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param is A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(InputStream& is) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') + s.Take(); +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); + + for (;; p += 16) { + const __m128i s = _mm_load_si128((const __m128i *)p); + const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + if (r != 0) { // some of characters is non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string + static const char whitespaces[4][17] = { + " ", + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + + const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); + const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); + const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + + for (;; p += 16) { + const __m128i s = _mm_load_si128((const __m128i *)p); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +#endif // RAPIDJSON_SSE2 + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream& is) { + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream& is) { + is.src_ = SkipWhitespace_SIMD(is.src_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam SourceEncoding Encoding of the input stream. + \tparam TargetEncoding Encoding of the parse output. + \tparam StackAllocator Allocator type for stack. +*/ +template +class GenericReader { +public: + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + + //! Constructor. + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); + + parseResult_.Clear(); + + ClearStackOnExit scope(*this); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (is.Peek() == '\0') { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (is.Peek() != '\0') { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } + + return parseResult_; + } + + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + return Parse(is, handler); + } + + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + +protected: + void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } + +private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); + + void ClearStack() { stack_.Clear(); } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + }; + + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (is.Peek() == '/') { + is.Take(); + + if (is.Peek() == '*') { + is.Take(); + while (true) { + if (is.Peek() == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + if (is.Take() == '*') { + if (is.Peek() == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + if (is.Take() == '/') + break; + } + } + } else if (is.Peek() == '/') { + is.Take(); + while (is.Peek() != '\0' && is.Take() != '\n') { } + } else { + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + } + + SkipWhitespace(is); + } + } + } + + // Parse object: { string : value, ... } + template + void ParseObject(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (!handler.StartObject()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (is.Peek() == '}') { + is.Take(); + if (!handler.EndObject(0)) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType memberCount = 0;;) { + if (is.Peek() != '"') + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + ParseString(is, handler, true); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (is.Take() != ':') + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++memberCount; + + switch (is.Take()) { + case ',': + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + if (!handler.EndObject(memberCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + break; + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (!handler.StartArray()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (is.Peek() == ']') { + is.Take(); + if (!handler.EndArray(0)) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType elementCount = 0;;) { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++elementCount; + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + switch (is.Take()) { + case ',': + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case ']': + if (!handler.EndArray(elementCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + break; + } + } + } + + template + void ParseNull(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); + + if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { + if (!handler.Null()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } + + template + void ParseTrue(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); + + if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { + if (!handler.Bool(true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } + + template + void ParseFalse(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); + + if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { + if (!handler.Bool(false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } + + // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream& is) { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = is.Take(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + } + return codepoint; + } + + template + class StackStream { + public: + typedef CharType Ch; + + StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) { + *stack_.template Push() = c; + ++length_; + } + size_t Length() const { return length_; } + Ch* Pop() { + return stack_.template Pop(length_); + } + + private: + StackStream(const StackStream&); + StackStream& operator=(const StackStream&); + + internal::Stack& stack_; + SizeType length_; + }; + + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream& is, Handler& handler, bool isKey = false) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + bool success = false; + if (parseFlags & kParseInsituFlag) { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + size_t length = s.PutEnd(head) - 1; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); + } + else { + StackStream stackStream(stack_); + ParseStringToStream(s, stackStream); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + SizeType length = static_cast(stackStream.Length()) - 1; + const typename TargetEncoding::Ch* const str = stackStream.Pop(); + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); + } + if (!success) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const char escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 +//!@endcond + + RAPIDJSON_ASSERT(is.Peek() == '\"'); + is.Take(); // Skip '\"' + + for (;;) { + Ch c = is.Peek(); + if (c == '\\') { // Escape + is.Take(); + Ch e = is.Take(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { + os.Put(escape[(unsigned char)e]); + } + else if (e == 'u') { // Unicode + unsigned codepoint = ParseHex4(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { + // Handle UTF-16 surrogate pair + if (is.Take() != '\\' || is.Take() != 'u') + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); + unsigned codepoint2 = ParseHex4(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); + } + else if (c == '"') { // Closing double quote + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); + else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); + else { + if (parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); + } + } + } + + template + class NumberStream; + + template + class NumberStream { + public: + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } + RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } + RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } + size_t Tell() { return is.Tell(); } + size_t Length() { return 0; } + const char* Pop() { return 0; } + + protected: + NumberStream& operator=(const NumberStream&); + + InputStream& is; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : NumberStream(reader, is), stackStream(reader.stack_) {} + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch TakePush() { + stackStream.Put((char)Base::is.Peek()); + return Base::is.Take(); + } + + size_t Length() { return stackStream.Length(); } + + const char* Pop() { + stackStream.Put('\0'); + return stackStream.Pop(); + } + + private: + StackStream stackStream; + }; + + template + void ParseNumber(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + NumberStream s(*this, copy.s); + + // Parse minus + bool minus = false; + if (s.Peek() == '-') { + minus = true; + s.Take(); + } + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + uint64_t i64 = 0; + bool use64bit = false; + int significandDigit = 0; + if (s.Peek() == '0') { + i = 0; + s.TakePush(); + } + else if (s.Peek() >= '1' && s.Peek() <= '9') { + i = static_cast(s.TakePush() - '0'); + + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 214748364) { // 2^31 = 2147483648 + if (i != 214748364 || s.Peek() > '8') { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 429496729) { // 2^32 - 1 = 4294967295 + if (i != 429496729 || s.Peek() > '5') { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + + // Parse 64bit int + bool useDouble = false; + double d = 0.0; + if (use64bit) { + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 + if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { + d = i64; + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 + if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { + d = i64; + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + + // Force double for big integer + if (useDouble) { + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + d = d * 10 + (s.TakePush() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + size_t decimalPosition; + if (s.Peek() == '.') { + s.Take(); + decimalPosition = s.Length(); + + if (!(s.Peek() >= '0' && s.Peek() <= '9')) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + + if (!useDouble) { +#if RAPIDJSON_64BIT + // Use i64 to store significand in 64-bit architecture + if (!use64bit) + i64 = i; + + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + break; + else { + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + --expFrac; + if (i64 != 0) + significandDigit++; + } + } + + d = (double)i64; +#else + // Use double to store significand in 32-bit architecture + d = use64bit ? (double)i64 : (double)i; +#endif + useDouble = true; + } + + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (significandDigit < 17) { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (d > 0.0) + significandDigit++; + } + else + s.TakePush(); + } + } + else + decimalPosition = s.Length(); // decimal position at the end of integer. + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (s.Peek() == 'e' || s.Peek() == 'E') { + if (!useDouble) { + d = use64bit ? i64 : i; + useDouble = true; + } + s.Take(); + + bool expMinus = false; + if (s.Peek() == '+') + s.Take(); + else if (s.Peek() == '-') { + s.Take(); + expMinus = true; + } + + if (s.Peek() >= '0' && s.Peek() <= '9') { + exp = s.Take() - '0'; + if (expMinus) { + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp >= 214748364) { // Issue #313: prevent overflow exponent + while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp > maxExp) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + } + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + bool cont = true; + size_t length = s.Length(); + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + cont = handler.Double(minus ? -d : d); + } + else { + if (use64bit) { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + if (!cont) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse any JSON value + template + void ParseValue(InputStream& is, Handler& handler) { + switch (is.Peek()) { + case 'n': ParseNull (is, handler); break; + case 't': ParseTrue (is, handler); break; + case 'f': ParseFalse (is, handler); break; + case '"': ParseString(is, handler); break; + case '{': ParseObject(is, handler); break; + case '[': ParseArray (is, handler); break; + default : + ParseNumber(is, handler); + break; + + } + } + + // Iterative Parsing + + // States + enum IterativeParsingState { + IterativeParsingStartState = 0, + IterativeParsingFinishState, + IterativeParsingErrorState, + + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingKeyValueDelimiterState, + IterativeParsingMemberValueState, + IterativeParsingMemberDelimiterState, + IterativeParsingObjectFinishState, + + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingElementDelimiterState, + IterativeParsingArrayFinishState, + + // Single value state + IterativeParsingValueState, + + cIterativeParsingStateCount + }; + + // Tokens + enum Token { + LeftBracketToken = 0, + RightBracketToken, + + LeftCurlyBracketToken, + RightCurlyBracketToken, + + CommaToken, + ColonToken, + + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, + + kTokenCount + }; + + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define N NumberToken +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; +#undef N +#undef N16 +//!@endcond + + if (sizeof(Ch) == 1 || unsigned(c) < 256) + return (Token)tokenMap[(unsigned char)c]; + else + return NumberToken; + } + + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number + }, + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + } + }; // End of G + + return (IterativeParsingState)G[state][token]; + } + + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + (void)token; + + switch (dst) { + case IterativeParsingErrorState: + return dst; + + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return dst; + } + } + + case IterativeParsingMemberKeyState: + ParseString(is, handler, true); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; + + case IterativeParsingKeyValueDelimiterState: + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; + + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; + + case IterativeParsingObjectFinishState: + { + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + case IterativeParsingArrayFinishState: + { + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + } + } + + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + switch (src) { + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; + } + } + + template + ParseResult IterativeParse(InputStream& is, Handler& handler) { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state, is); + break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + + return parseResult_; + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader, UTF8<> > Reader; + +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_READER_H_ diff --git a/contrib/rapidjson/include/rapidjson/stringbuffer.h b/contrib/rapidjson/include/rapidjson/stringbuffer.h new file mode 100644 index 000000000..1c9c80b79 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/stringbuffer.h @@ -0,0 +1,93 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "rapidjson.h" + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +class GenericStringBuffer { +public: + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} + GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { + if (&rhs != this) + stack_ = std::move(rhs.stack_); + return *this; + } +#endif + + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.ShrinkToFit(); + stack_.template Pop(1); + } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; + +private: + // Prohibit copy constructor & assignment operator. + GenericStringBuffer(const GenericStringBuffer&); + GenericStringBuffer& operator=(const GenericStringBuffer&); +}; + +//! String buffer with UTF8 encoding +typedef GenericStringBuffer > StringBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { + std::memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/contrib/rapidjson/include/rapidjson/writer.h b/contrib/rapidjson/include/rapidjson/writer.h new file mode 100644 index 000000000..874faa881 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/writer.h @@ -0,0 +1,395 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "rapidjson.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include "internal/dtoa.h" +#include "internal/itoa.h" +#include "stringbuffer.h" +#include // placement new + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output os. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. + \note implements Handler concept +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> +class Writer { +public: + typedef typename SourceEncoding::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param stackAllocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit + Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + + explicit + Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. + + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); + + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream& os) { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } + + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const { + return hasRoot_ && level_stack_.Empty(); + } + + /*!@name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { Prefix(kNullType); return WriteNull(); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } + bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } + bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } + bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } + + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } + + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + Prefix(kStringType); + return WriteString(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + bool ret = WriteEndObject(); + if (level_stack_.Empty()) // end of json text + os_->Flush(); + return ret; + } + + bool StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } + + bool EndArray(SizeType elementCount = 0) { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + bool ret = WriteEndArray(); + if (level_stack_.Empty()) // end of json text + os_->Flush(); + return ret; + } + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} + +protected: + //! Information for each nested level + struct Level { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; + + static const size_t kDefaultLevelDepth = 32; + + bool WriteNull() { + os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; + } + + bool WriteBool(bool b) { + if (b) { + os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); + } + else { + os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); + } + return true; + } + + bool WriteInt(int i) { + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } + + bool WriteUint(unsigned u) { + char buffer[10]; + const char* end = internal::u32toa(u, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } + + bool WriteInt64(int64_t i64) { + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* end = internal::u64toa(u64, buffer); + for (char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } + + bool WriteDouble(double d) { + char buffer[25]; + char* end = internal::dtoa(d, buffer); + for (char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } + + bool WriteString(const Ch* str, SizeType length) { + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + os_->Put('\"'); + GenericStringStream is(str); + while (is.Tell() < length) { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { + // Unicode escaping + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + os_->Put('\\'); + os_->Put('u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + os_->Put(hexDigits[(codepoint >> 12) & 15]); + os_->Put(hexDigits[(codepoint >> 8) & 15]); + os_->Put(hexDigits[(codepoint >> 4) & 15]); + os_->Put(hexDigits[(codepoint ) & 15]); + } + else { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + os_->Put(hexDigits[(lead >> 12) & 15]); + os_->Put(hexDigits[(lead >> 8) & 15]); + os_->Put(hexDigits[(lead >> 4) & 15]); + os_->Put(hexDigits[(lead ) & 15]); + os_->Put('\\'); + os_->Put('u'); + os_->Put(hexDigits[(trail >> 12) & 15]); + os_->Put(hexDigits[(trail >> 8) & 15]); + os_->Put(hexDigits[(trail >> 4) & 15]); + os_->Put(hexDigits[(trail ) & 15]); + } + } + else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { + is.Take(); + os_->Put('\\'); + os_->Put(escape[(unsigned char)c]); + if (escape[(unsigned char)c] == 'u') { + os_->Put('0'); + os_->Put('0'); + os_->Put(hexDigits[(unsigned char)c >> 4]); + os_->Put(hexDigits[(unsigned char)c & 0xF]); + } + } + else + if (!Transcoder::Transcode(is, *os_)) + return false; + } + os_->Put('\"'); + return true; + } + + bool WriteStartObject() { os_->Put('{'); return true; } + bool WriteEndObject() { os_->Put('}'); return true; } + bool WriteStartArray() { os_->Put('['); return true; } + bool WriteEndArray() { os_->Put(']'); return true; } + + void Prefix(Type type) { + (void)type; + if (level_stack_.GetSize() != 0) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } + + OutputStream* os_; + internal::Stack level_stack_; + bool hasRoot_; + +private: + // Prohibit copy constructor & assignment operator. + Writer(const Writer&); + Writer& operator=(const Writer&); +}; + +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(static_cast(11 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(static_cast(10 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(static_cast(21 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(static_cast(20 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteDouble(double d) { + char *buffer = os_->Push(25); + char* end = internal::dtoa(d, buffer); + os_->Pop(static_cast(25 - (end - buffer))); + return true; +} + +RAPIDJSON_NAMESPACE_END + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/rapidjson/license.txt b/contrib/rapidjson/license.txt new file mode 100644 index 000000000..7ccc161c8 --- /dev/null +++ b/contrib/rapidjson/license.txt @@ -0,0 +1,57 @@ +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. + +If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. +If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. +A copy of the MIT License is included in this file. + +Other dependencies and licenses: + +Open Source Software Licensed Under the BSD License: +-------------------------------------------------------------------- + +The msinttypes r29 +Copyright (c) 2006-2013 Alexander Chemeris +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* 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. +* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS AND 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. + +Open Source Software Licensed Under the JSON License: +-------------------------------------------------------------------- + +json.org +Copyright (c) 2002 JSON.org +All Rights Reserved. + +JSON_checker +Copyright (c) 2002 JSON.org +All Rights Reserved. + + +Terms of the JSON License: +--------------------------------------------------- + +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 shall be used for Good, not Evil. + +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. + + +Terms of the MIT License: +-------------------------------------------------------------------- + +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. diff --git a/contrib/rapidjson/readme.md b/contrib/rapidjson/readme.md new file mode 100644 index 000000000..fb270fb96 --- /dev/null +++ b/contrib/rapidjson/readme.md @@ -0,0 +1,129 @@ +![](doc/logo/rapidjson.png) + +![](https://img.shields.io/badge/release-v1.0.2-blue.png) + +## A fast JSON parser/generator for C++ with both SAX/DOM style API + +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. + +* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) +* RapidJSON Documentation + * [English](http://rapidjson.org/) + * [简体中文](http://rapidjson.org/zh-cn/) + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. + +## Build status + +| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] | +| :---------------: | :-----------------: | :-------------------: | +| ![lin-badge] | ![win-badge] | ![cov-badge] | + +[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" +[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master +[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master + +## Introduction + +RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/). + +* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. + +* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. + +* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL. + +* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. + +* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). + +More features can be read [here](doc/features.md). + +JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404. More information about JSON can be obtained at +* [Introducing JSON](http://json.org/) +* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt) +* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm) + +## Compatibility + +RapidJSON is cross-platform. Some platform/compiler combinations which have been tested are shown as follows. +* Visual C++ 2008/2010/2013 on Windows (32/64-bit) +* GNU C++ 3.8.x on Cygwin +* Clang 3.4 on Mac OS X (32/64-bit) and iOS +* Clang 3.4 on Android NDK + +Users can build and run the unit tests on their platform/compiler. + +## Installation + +RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. + +RapidJSON uses following software as its dependencies: +* [CMake](http://www.cmake.org) as a general build tool +* (optional)[Doxygen](http://www.doxygen.org) to build documentation +* (optional)[googletest](https://code.google.com/p/googletest/) for unit and performance testing + +To generate user documentation and run tests please proceed with the steps below: + +1. Execute `git submodule update --init` to get the files of thirdparty submodules (google test). +2. Create directory called `build` in rapidjson source directory. +3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application. +4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory. + +On successfull build you will find compiled test and example binaries in `bin` +directory. The generated documentation will be available in `doc/html` +directory of the build tree. To run tests after finished build please run `make +test` or `ctest` from your build tree. You can get detailed output using `ctest +-V` command. + +It is possible to install library system-wide by running `make install` command +from the build tree with administrative privileges. This will install all files +according to system preferences. Once RapidJSON is installed, it is possible +to use it from other CMake projects by adding `find_package(RapidJSON)` line to +your CMakeLists.txt. + +## Usage at a glance + +This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string. + +~~~~~~~~~~cpp +// rapidjson/example/simpledom/simpledom.cpp` +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include + +using namespace rapidjson; + +int main() { + // 1. Parse a JSON string into DOM. + const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; + Document d; + d.Parse(json); + + // 2. Modify it by DOM. + Value& s = d["stars"]; + s.SetInt(s.GetInt() + 1); + + // 3. Stringify the DOM + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); + + // Output {"project":"rapidjson","stars":11} + std::cout << buffer.GetString() << std::endl; + return 0; +} +~~~~~~~~~~ + +Note that this example did not handle potential errors. + +The following diagram shows the process. + +![simpledom](doc/diagram/simpledom.png) + +More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available. diff --git a/contrib/zlib/gzwrite.c b/contrib/zlib/gzwrite.c index aa767fbf6..3ed161f44 100644 --- a/contrib/zlib/gzwrite.c +++ b/contrib/zlib/gzwrite.c @@ -438,7 +438,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, # endif #else # ifdef HAS_snprintf_void - snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, + snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen((char *)(state->in)); # else diff --git a/doc/dox.h b/doc/dox.h index aad0925bd..cd9214453 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -145,7 +145,7 @@ project dependencies. Link to /lib//assimp.lib. config project configs. For static linking, use release/debug. See the sections below on this page for more information on the other build configs. If done correctly you should now be able to compile, link, -run and use the application. If the linker complains about some integral functions being defined twice you propably have +run and use the application. If the linker complains about some integral functions being defined twice you probably have mixed the runtimes. Recheck the project configuration (project properties -> C++ -> Code generation -> Runtime) if you use static runtimes (Multithreaded / Multithreaded Debug) or dynamic runtimes (Multithreaded DLL / Multithreaded Debug DLL). Choose the assimp linker lib accordingly. @@ -287,7 +287,7 @@ bool DoTheImportThing( const std::string& pFile) // And have it read the given file with some example postprocessing // Usually - if speed is not the most important aspect for you - you'll - // propably to request more postprocessing than we do in this example. + // probably to request more postprocessing than we do in this example. const aiScene* scene = importer.ReadFile( pFile, aiProcess_CalcTangentSpace | aiProcess_Triangulate | diff --git a/include/assimp/Compiler/pstdint.h b/include/assimp/Compiler/pstdint.h index 5bc322fab..3692a8aef 100644 --- a/include/assimp/Compiler/pstdint.h +++ b/include/assimp/Compiler/pstdint.h @@ -3,13 +3,13 @@ * BSD License: **************************************************************************** * - * Copyright (c) 2005-2007 Paul Hsieh + * Copyright (c) 2005-2011 Paul Hsieh * 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 @@ -17,7 +17,7 @@ * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. @@ -31,7 +31,7 @@ * **************************************************************************** * - * Version 0.1.10 + * Version 0.1.12 * * The ANSI C standard committee, for the C99 standard, specified the * inclusion of a new standard include file called stdint.h. This is @@ -172,12 +172,15 @@ * * Acknowledgements * + * Edited by Philip G. Lee 2011 to avoid overlap with sys/types.h + * * The following people have made significant contributions to the * development and testing of this file: * * Chris Howie * John Steele Scott * Dave Thorup + * John Dill * */ @@ -190,7 +193,7 @@ * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. */ -#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)))) && !defined (_PSTDINT_H_INCLUDED) && !defined(_STDINT) +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED) #include #define _PSTDINT_H_INCLUDED # ifndef PRINTF_INT64_MODIFIER @@ -300,17 +303,10 @@ * definitions. */ -#ifndef UINT8_MAX -# define UINT8_MAX 0xff -#endif -#ifndef uint8_t -# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) - typedef unsigned char uint8_t; -# define UINT8_C(v) ((uint8_t) v) -# else -# error "Platform not supported" -# endif -#endif + +// Avoid overlap with sys/types.h +#ifndef __int8_t_defined +#define __int8_t_defined #ifndef INT8_MAX # define INT8_MAX 0x7f @@ -320,13 +316,110 @@ #endif #ifndef int8_t # if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) - typedef signed char int8_t; +typedef signed char int8_t; # define INT8_C(v) ((int8_t) v) # else # error "Platform not supported" # endif #endif +#ifndef INT16_MAX +# define INT16_MAX 0x7fff +#endif +#ifndef INT16_MIN +# define INT16_MIN INT16_C(0x8000) +#endif +#ifndef int16_t +#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) +typedef signed int int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +#elif (SHRT_MAX == INT16_MAX) +typedef signed short int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT32_MAX +# define INT32_MAX (0x7fffffffL) +#endif +#ifndef INT32_MIN +# define INT32_MIN INT32_C(0x80000000) +#endif +#ifndef int32_t +#if ((LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)) && ! defined(__FreeBSD__) +typedef signed long int32_t; +# define INT32_C(v) v ## L +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (INT_MAX == INT32_MAX) +typedef signed int int32_t; +# define INT32_C(v) v +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#elif (SHRT_MAX == INT32_MAX) +typedef signed short int32_t; +# define INT32_C(v) ((short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +// 64-bit shit seems more tricky. Philip Lee +/* +* The macro stdint_int64_defined is temporarily used to record +* whether or not 64 integer support is available. It must be +* defined for any 64 integer extensions for new platforms that are +* added. +*/ +#undef stdint_int64_defined +#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) +# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S) +# define stdint_int64_defined +typedef long long int64_t; +# endif +#endif +#if !defined (stdint_int64_defined) +# if defined(__GNUC__) +# define stdint_int64_defined +# ifndef __FreeBSD__ + __extension__ typedef long long int64_t; +# endif +# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) +# define stdint_int64_defined +typedef long long int64_t; +# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) +# define stdint_int64_defined +typedef __int64 int64_t; +# endif +#endif + +#endif /*ifndef __int8_t_defined*/ + +#ifndef UINT8_MAX +# define UINT8_MAX 0xff +#endif +#ifndef uint8_t +# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) + typedef unsigned char uint8_t; +# define UINT8_C(v) ((uint8_t) v) +# else +# error "Platform not supported" +# endif +#endif + #ifndef UINT16_MAX # define UINT16_MAX 0xffff #endif @@ -348,35 +441,11 @@ #endif #endif -#ifndef INT16_MAX -# define INT16_MAX 0x7fff -#endif -#ifndef INT16_MIN -# define INT16_MIN INT16_C(0x8000) -#endif -#ifndef int16_t -#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) - typedef signed int int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "" -# endif -#elif (SHRT_MAX == INT16_MAX) - typedef signed short int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -#else -#error "Platform not supported" -#endif -#endif - #ifndef UINT32_MAX # define UINT32_MAX (0xffffffffUL) #endif #ifndef uint32_t -#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) +#if ((ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)) && ! defined(__FreeBSD__) typedef unsigned long uint32_t; # define UINT32_C(v) v ## UL # ifndef PRINTF_INT32_MODIFIER @@ -399,36 +468,6 @@ #endif #endif -#ifndef INT32_MAX -# define INT32_MAX (0x7fffffffL) -#endif -#ifndef INT32_MIN -# define INT32_MIN INT32_C(0x80000000) -#endif -#ifndef int32_t -#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) - typedef signed long int32_t; -# define INT32_C(v) v ## L -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -#elif (INT_MAX == INT32_MAX) - typedef signed int int32_t; -# define INT32_C(v) v -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#elif (SHRT_MAX == INT32_MAX) - typedef signed short int32_t; -# define INT32_C(v) ((short) (v)) -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#else -#error "Platform not supported" -#endif -#endif - /* * The macro stdint_int64_defined is temporarily used to record * whether or not 64 integer support is available. It must be @@ -438,10 +477,11 @@ #undef stdint_int64_defined #if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) -# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S) +# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S) # define stdint_int64_defined - typedef long long int64_t; - typedef unsigned long long uint64_t; +# ifndef __FreeBSD__ + typedef unsigned long long uint64_t; +# endif # define UINT64_C(v) v ## ULL # define INT64_C(v) v ## LL # ifndef PRINTF_INT64_MODIFIER @@ -453,8 +493,9 @@ #if !defined (stdint_int64_defined) # if defined(__GNUC__) # define stdint_int64_defined - __extension__ typedef long long int64_t; - __extension__ typedef unsigned long long uint64_t; +# ifndef __FreeBSD__ + __extension__ typedef unsigned long long uint64_t; +# endif # define UINT64_C(v) v ## ULL # define INT64_C(v) v ## LL # ifndef PRINTF_INT64_MODIFIER @@ -462,7 +503,6 @@ # endif # elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) # define stdint_int64_defined - typedef long long int64_t; typedef unsigned long long uint64_t; # define UINT64_C(v) v ## ULL # define INT64_C(v) v ## LL @@ -471,7 +511,6 @@ # endif # elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) # define stdint_int64_defined - typedef __int64 int64_t; typedef unsigned __int64 uint64_t; # define UINT64_C(v) v ## UI64 # define INT64_C(v) v ## I64 @@ -616,10 +655,12 @@ * stdint.h. */ +#ifndef __FreeBSD__ typedef int_least8_t int_fast8_t; typedef uint_least8_t uint_fast8_t; typedef int_least16_t int_fast16_t; typedef uint_least16_t uint_fast16_t; +#endif typedef int_least32_t int_fast32_t; typedef uint_least32_t uint_fast32_t; #define UINT_FAST8_MAX UINT_LEAST8_MAX @@ -677,7 +718,7 @@ typedef uint_least32_t uint_fast32_t; # elif defined (__i386__) || defined (_WIN32) || defined (WIN32) # define stdint_intptr_bits 32 # elif defined (__INTEL_COMPILER) -/* TODO -- what will Intel do about x86-64? */ +/* TODO -- what did Intel do about x86-64? */ # endif # ifdef stdint_intptr_bits @@ -707,8 +748,15 @@ typedef uint_least32_t uint_fast32_t; # ifndef UINTPTR_C # define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) # endif - typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; - typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; +// Philip , need to check if [u]intprt_t is already defined... +# ifndef __uintptr_t_defined +# define __uintptr_t_defined + typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; +# endif /*uintptr_t*/ +# ifndef __intptr_t_defined +# define __intptr_t_defined + typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; +# endif /*__intptr_t_defined*/ # else /* TODO -- This following is likely wrong for some platforms, and does nothing for the definition of uintptr_t. */ @@ -727,3 +775,73 @@ typedef uint_least32_t uint_fast32_t; #endif +#if defined (__TEST_PSTDINT_FOR_CORRECTNESS) + +/* + * Please compile with the maximum warning settings to make sure macros are not + * defined more than once. + */ + +#include +#include +#include + +#define glue3_aux(x,y,z) x ## y ## z +#define glue3(x,y,z) glue3_aux(x,y,z) + +#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0); +#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0); + +#define DECL(us,bits) glue3(DECL,us,) (bits) + +#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits) + +int main () { + DECL(I,8) + DECL(U,8) + DECL(I,16) + DECL(U,16) + DECL(I,32) + DECL(U,32) +#ifdef INT64_MAX + DECL(I,64) + DECL(U,64) +#endif + intmax_t imax = INTMAX_C(0); + uintmax_t umax = UINTMAX_C(0); + char str0[256], str1[256]; + + sprintf (str0, "%d %x\n", 0, ~0); + + sprintf (str1, "%d %x\n", i8, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1); + sprintf (str1, "%u %x\n", u8, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1); + sprintf (str1, "%d %x\n", i16, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1); + sprintf (str1, "%u %x\n", u16, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1); + sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1); + sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1); +#ifdef INT64_MAX + sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1); +#endif + sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1); + sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1); + + TESTUMAX(8); + TESTUMAX(16); + TESTUMAX(32); +#ifdef INT64_MAX + TESTUMAX(64); +#endif + + return EXIT_SUCCESS; +} + +#endif diff --git a/include/assimp/Compiler/pushpack1.h b/include/assimp/Compiler/pushpack1.h index e55202665..73973c50d 100644 --- a/include/assimp/Compiler/pushpack1.h +++ b/include/assimp/Compiler/pushpack1.h @@ -37,7 +37,7 @@ #if defined(_MSC_VER) -// C4103: Packing was changed after the inclusion of the header, propably missing #pragma pop +// C4103: Packing was changed after the inclusion of the header, probably missing #pragma pop # pragma warning (disable : 4103) #endif diff --git a/include/assimp/DefaultLogger.hpp b/include/assimp/DefaultLogger.hpp index 488f39d27..52574d5ea 100644 --- a/include/assimp/DefaultLogger.hpp +++ b/include/assimp/DefaultLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -135,7 +135,7 @@ private: // ---------------------------------------------------------------------- /** @briefPrivate construction for internal use by create(). * @param severity Logging granularity */ - DefaultLogger(LogSeverity severity); + explicit DefaultLogger(LogSeverity severity); // ---------------------------------------------------------------------- /** @briefDestructor */ diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index 9520d2367..6cc231b3d 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index 321509de6..abd7e5837 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 917c980d0..10c62e55d 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -114,6 +114,11 @@ namespace Assimp { * threads for loading, each thread should maintain its own Importer instance. */ class ASSIMP_API Importer { +public: + /** + * @brief The upper limit for hints. + */ + static const unsigned int MaxLenHint = 200; public: @@ -453,6 +458,8 @@ public: * to the #Importer instance. */ const aiScene* ApplyPostProcessing(unsigned int pFlags); + const aiScene* ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ); + // ------------------------------------------------------------------- /** @brief Reads the given file and returns its contents if successful. * diff --git a/include/assimp/LogStream.hpp b/include/assimp/LogStream.hpp index b5237599c..477fe5321 100644 --- a/include/assimp/LogStream.hpp +++ b/include/assimp/LogStream.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/Logger.hpp b/include/assimp/Logger.hpp index 7e1c52908..7f355b5bf 100644 --- a/include/assimp/Logger.hpp +++ b/include/assimp/Logger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -160,7 +160,7 @@ protected: Logger(); /** Construction with a given log severity */ - Logger(LogSeverity severity); + explicit Logger(LogSeverity severity); // ---------------------------------------------------------------------- /** @brief Called as a request to write a specific debug message diff --git a/include/assimp/NullLogger.hpp b/include/assimp/NullLogger.hpp index b5b2f915f..64b59a4a0 100644 --- a/include/assimp/NullLogger.hpp +++ b/include/assimp/NullLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index 905cc31ca..8b069c82e 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index a8559cd06..0caeff673 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -1,5 +1,43 @@ -/** @file ai_assert.h - */ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +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 AI_DEBUG_H_INC #define AI_DEBUG_H_INC diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 914294605..0acb84532 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/camera.h b/include/assimp/camera.h index 1641aec5b..37f1bdaa0 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/cexport.h b/include/assimp/cexport.h index 4afa3156a..71cb1f8ec 100644 --- a/include/assimp/cexport.h +++ b/include/assimp/cexport.h @@ -86,13 +86,20 @@ ASSIMP_API size_t aiGetExportFormatCount(void); // -------------------------------------------------------------------------------- /** Returns a description of the nth export file format. Use #aiGetExportFormatCount() - * to learn how many export formats are supported. + * to learn how many export formats are supported. The description must be released by + * calling aiReleaseExportFormatDescription afterwards. * @param pIndex Index of the export format to retrieve information for. Valid range is * 0 to #aiGetExportFormatCount() * @return A description of that specific export format. NULL if pIndex is out of range. */ ASSIMP_API const C_STRUCT aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex); +// -------------------------------------------------------------------------------- +/** Release a description of the nth export file format. Must be returned by +* aiGetExportFormatDescription +* @param desc Pointer to the description +*/ +ASSIMP_API void aiReleaseExportFormatDescription( const C_STRUCT aiExportFormatDesc *desc ); // -------------------------------------------------------------------------------- /** Create a modifiable copy of a scene. diff --git a/include/assimp/cfileio.h b/include/assimp/cfileio.h index 0c53142cc..d91974b78 100644 --- a/include/assimp/cfileio.h +++ b/include/assimp/cfileio.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/cimport.h b/include/assimp/cimport.h index 78e2ad397..de0cbae30 100644 --- a/include/assimp/cimport.h +++ b/include/assimp/cimport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSIMP_H_INC #define AI_ASSIMP_H_INC #include "types.h" -#include +#include "importerdesc.h" #ifdef __cplusplus extern "C" { diff --git a/include/assimp/color4.h b/include/assimp/color4.h index 1e2070b98..2a2c338c8 100644 --- a/include/assimp/color4.h +++ b/include/assimp/color4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -59,7 +59,7 @@ public: aiColor4t () : r(), g(), b(), a() {} aiColor4t (TReal _r, TReal _g, TReal _b, TReal _a) : r(_r), g(_g), b(_b), a(_a) {} - aiColor4t (TReal _r) : r(_r), g(_r), b(_r), a(_r) {} + explicit aiColor4t (TReal _r) : r(_r), g(_r), b(_r), a(_r) {} aiColor4t (const aiColor4t& o) : r(o.r), g(o.g), b(o.b), a(o.a) {} @@ -86,7 +86,12 @@ public: public: // Red, green, blue and alpha color values - TReal r, g, b, a; + union { + struct { + TReal r, g, b, a; + }; + TReal c[ 4 ]; + }; } PACK_STRUCT; // !struct aiColor4D typedef aiColor4t aiColor4D; @@ -94,7 +99,12 @@ typedef aiColor4t aiColor4D; #else struct aiColor4D { - float r, g, b, a; + union { + struct { + float r, g, b, a; + }; + float c[ 4 ]; + }; } PACK_STRUCT; #endif // __cplusplus diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index 28cf68b4e..d69814714 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/config.h b/include/assimp/config.h index 4b2546760..3db8a5697 100644 --- a/include/assimp/config.h +++ b/include/assimp/config.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -561,6 +561,15 @@ enum aiComponent #define AI_CONFIG_IMPORT_FBX_READ_MATERIALS \ "IMPORT_FBX_READ_MATERIALS" +// --------------------------------------------------------------------------- +/** @brief Set whether the fbx importer will read embedded textures. + * + * The default value is true (1) + * Property type: bool + */ +#define AI_CONFIG_IMPORT_FBX_READ_TEXTURES \ + "IMPORT_FBX_READ_TEXTURES" + // --------------------------------------------------------------------------- /** @brief Set whether the fbx importer will read cameras. * @@ -886,16 +895,6 @@ enum aiComponent */ #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION" -// --------------------------------------------------------------------------- -/** @brief Specifies whether the Collada loader will invert the transparency value. - * - * If this property is set to true, the transparency value will be interpreted as the - * inverse of the usual transparency. This is useful because lots of exporters does - * not respect the standard and do the opposite of what is normally expected. - * Property type: Bool. Default value: false. - */ -#define AI_CONFIG_IMPORT_COLLADA_INVERT_TRANSPARENCY "IMPORT_COLLADA_INVERT_TRANSPARENCY" - // ---------- All the Export defines ------------ /** @brief Specifies the xfile use double for real values of float diff --git a/include/assimp/defs.h b/include/assimp/defs.h index 3129a027b..e90be4a99 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index c1c46a7bd..b2b123aca 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/light.h b/include/assimp/light.h index d3990ea90..331bc3586 100644 --- a/include/assimp/light.h +++ b/include/assimp/light.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/material.h b/include/assimp/material.h index e4d4565db..6c222a040 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -735,7 +735,7 @@ public: C_STRUCT aiString* path, aiTextureMapping* mapping = NULL, unsigned int* uvindex = NULL, - float* blend = NULL, + float* blend = NULL, aiTextureOp* op = NULL, aiTextureMapMode* mapmode = NULL) const; @@ -1344,9 +1344,9 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialProperty( * arrays remains unmodified and pMax is set to 0.*/ // --------------------------------------------------------------------------- ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( - const C_STRUCT aiMaterial* pMat, + const C_STRUCT aiMaterial* pMat, const char* pKey, - unsigned int type, + unsigned int type, unsigned int index, float* pOut, unsigned int* pMax); @@ -1376,7 +1376,7 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( inline aiReturn aiGetMaterialFloat(const aiMaterial* pMat, const char* pKey, unsigned int type, - unsigned int index, + unsigned int index, float* pOut) { return aiGetMaterialFloatArray(pMat,pKey,type,index,pOut,(unsigned int*)0x0); @@ -1397,11 +1397,11 @@ inline aiReturn aiGetMaterialFloat(const aiMaterial* pMat, * * See the sample for aiGetMaterialFloatArray for more information.*/ ASSIMP_API C_ENUM aiReturn aiGetMaterialIntegerArray(const C_STRUCT aiMaterial* pMat, - const char* pKey, + const char* pKey, unsigned int type, unsigned int index, - int* pOut, - unsigned int* pMax); + int* pOut, + unsigned int* pMax); #ifdef __cplusplus @@ -1437,9 +1437,9 @@ inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial* pMat, // --------------------------------------------------------------------------- ASSIMP_API C_ENUM aiReturn aiGetMaterialColor(const C_STRUCT aiMaterial* pMat, const char* pKey, - unsigned int type, + unsigned int type, unsigned int index, - C_STRUCT aiColor4D* pOut); + C_STRUCT aiColor4D* pOut); // --------------------------------------------------------------------------- @@ -1449,9 +1449,9 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialColor(const C_STRUCT aiMaterial* pMat, // --------------------------------------------------------------------------- ASSIMP_API C_ENUM aiReturn aiGetMaterialUVTransform(const C_STRUCT aiMaterial* pMat, const char* pKey, - unsigned int type, + unsigned int type, unsigned int index, - C_STRUCT aiUVTransform* pOut); + C_STRUCT aiUVTransform* pOut); // --------------------------------------------------------------------------- @@ -1461,7 +1461,7 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialUVTransform(const C_STRUCT aiMaterial* p // --------------------------------------------------------------------------- ASSIMP_API C_ENUM aiReturn aiGetMaterialString(const C_STRUCT aiMaterial* pMat, const char* pKey, - unsigned int type, + unsigned int type, unsigned int index, C_STRUCT aiString* pOut); diff --git a/include/assimp/material.inl b/include/assimp/material.inl index ed37148ff..994e608b4 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index bc7a805fc..6b2350efc 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -152,7 +152,7 @@ public: * vector called "from" into another vector called "to". * Input : from[3], to[3] which both must be *normalized* non-zero vectors * Output: mtx[3][3] -- a 3x3 matrix in colum-major form - * Authors: Tomas Möller, John Hughes + * Authors: Tomas M�ller, John Hughes * "Efficiently Building a Matrix to Rotate One Vector to Another" * Journal of Graphics Tools, 4(4):1-4, 1999 */ @@ -161,10 +161,15 @@ public: public: - - TReal a1, a2, a3; - TReal b1, b2, b3; - TReal c1, c2, c3; + union { + struct { + TReal a1, a2, a3; + TReal b1, b2, b3; + TReal c1, c2, c3; + }; + TReal m[ 3 ][ 3 ]; + TReal mData[ 9 ]; + }; } PACK_STRUCT; typedef aiMatrix3x3t aiMatrix3x3; @@ -172,13 +177,18 @@ typedef aiMatrix3x3t aiMatrix3x3; #else struct aiMatrix3x3 { - - float a1, a2, a3; - float b1, b2, b3; - float c1, c2, c3; + union { + struct { + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; + }; + float m[ 3 ][ 3 ]; + float mData[ 9 ]; + }; } PACK_STRUCT; -#endif +#endif // __cplusplus #include "./Compiler/poppack1.h" diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl index 7006418b7..fc7d96c3a 100644 --- a/include/assimp/matrix3x3.inl +++ b/include/assimp/matrix3x3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -241,7 +241,7 @@ inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& to, aiMatrix4x4t& out); public: - - TReal a1, a2, a3, a4; - TReal b1, b2, b3, b4; - TReal c1, c2, c3, c4; - TReal d1, d2, d3, d4; - + union { + struct { + TReal a1, a2, a3, a4; + TReal b1, b2, b3, b4; + TReal c1, c2, c3, c4; + TReal d1, d2, d3, d4; + }; + TReal m[ 4 ][ 4 ]; + TReal mData[ 16 ]; + }; } PACK_STRUCT; typedef aiMatrix4x4t aiMatrix4x4; @@ -235,11 +239,17 @@ typedef aiMatrix4x4t aiMatrix4x4; #else struct aiMatrix4x4 { - float a1, a2, a3, a4; - float b1, b2, b3, b4; - float c1, c2, c3, c4; - float d1, d2, d3, d4; -}; + union { + struct { + float a1, a2, a3, a4; + float b1, b2, b3, b4; + float c1, c2, c3, c4; + float d1, d2, d3, d4; + }; + float m[ 4 ][ 4 ]; + float mData[ 16 ]; + }; +} PACK_STRUCT; #endif // __cplusplus diff --git a/include/assimp/matrix4x4.inl b/include/assimp/matrix4x4.inl index c1640c290..9ce794f0a 100644 --- a/include/assimp/matrix4x4.inl +++ b/include/assimp/matrix4x4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -238,16 +238,22 @@ inline aiMatrix4x4t& aiMatrix4x4t::Inverse() // ---------------------------------------------------------------------------------------- template -inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) -{ +inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { + if (p_iIndex > 3) { + return NULL; + } + // XXX this is UB. Has been for years. The fact that it works now does not make it better. return &this->a1 + p_iIndex * 4; } // ---------------------------------------------------------------------------------------- template -inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const -{ +inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const { + if (p_iIndex > 3) { + return NULL; + } + // XXX same return &this->a1 + p_iIndex * 4; } @@ -516,7 +522,7 @@ inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& pRotMatrix); + explicit aiQuaterniont( const aiMatrix3x3t& pRotMatrix); /** Construct from euler angles */ aiQuaterniont( TReal rotx, TReal roty, TReal rotz); @@ -69,7 +69,7 @@ public: aiQuaterniont( aiVector3t axis, TReal angle); /** Construct from a normalized quaternion stored in a vec3 */ - aiQuaterniont( aiVector3t normalized); + explicit aiQuaterniont( aiVector3t normalized); /** Returns a matrix representation of the quaternion */ aiMatrix3x3t GetMatrix() const; diff --git a/include/assimp/quaternion.inl b/include/assimp/quaternion.inl index 06b9ef238..db27c25ff 100644 --- a/include/assimp/quaternion.inl +++ b/include/assimp/quaternion.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/scene.h b/include/assimp/scene.h index 2c51eaf79..8987ac6a3 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -109,7 +109,9 @@ struct aiNode /** The number of meshes of this node. */ unsigned int mNumMeshes; - /** The meshes of this node. Each entry is an index into the mesh */ + /** The meshes of this node. Each entry is an index into the + * mesh list of the #aiScene. + */ unsigned int* mMeshes; /** Metadata associated with this node or NULL if there is no metadata. @@ -135,7 +137,7 @@ struct aiNode /** Construction from a specific name */ - aiNode(const std::string& name) + explicit aiNode(const std::string& name) // set all members to zero by default : mName(name) , mParent(NULL) diff --git a/include/assimp/texture.h b/include/assimp/texture.h index 40faf497e..ee3ee3149 100644 --- a/include/assimp/texture.h +++ b/include/assimp/texture.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -116,6 +116,10 @@ struct aiTexel * 2. Compressed textures stored in a file format like png or jpg. The raw file * bytes are given so the application must utilize an image decoder (e.g. DevIL) to * get access to the actual color data. + * + * Embedded textures are referenced from materials using strings like "*0", "*1", etc. + * as the texture paths (a single asterisk character followed by the + * zero-based index of the texture in the aiScene::mTextures array). */ struct aiTexture { diff --git a/include/assimp/types.h b/include/assimp/types.h index 82be2d62f..592d5c64d 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -160,7 +160,7 @@ struct aiColor3D #ifdef __cplusplus aiColor3D () : r(0.0f), g(0.0f), b(0.0f) {} aiColor3D (float _r, float _g, float _b) : r(_r), g(_g), b(_b) {} - aiColor3D (float _r) : r(_r), g(_r), b(_r) {} + explicit aiColor3D (float _r) : r(_r), g(_r), b(_r) {} aiColor3D (const aiColor3D& o) : r(o.r), g(o.g), b(o.b) {} /** Component-wise comparison */ diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index b6cb95efc..2342f1ebd 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -95,7 +95,13 @@ public: template operator aiVector2t () const; - TReal x, y; + union { + struct { + TReal x, y; + }; + TReal v[ 2 ]; + }; + } PACK_STRUCT; typedef aiVector2t aiVector2D; @@ -103,7 +109,12 @@ typedef aiVector2t aiVector2D; #else struct aiVector2D { - float x,y; + union { + struct { + float x, y; + }; + float v[ 2 ]; + }; }; #endif // __cplusplus diff --git a/include/assimp/vector2.inl b/include/assimp/vector2.inl index 6553100ca..ae823fc1a 100644 --- a/include/assimp/vector2.inl +++ b/include/assimp/vector2.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index b19de34c8..0358045e3 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -116,6 +116,8 @@ public: /** @brief Normalize the vector */ aiVector3t& Normalize(); + /** @brief Normalize the vector with extra check for zero vectors */ + aiVector3t& NormalizeSafe(); /** @brief Componentwise multiplication of two vectors * @@ -123,7 +125,12 @@ public: * @param o Second factor */ const aiVector3t SymMul(const aiVector3t& o); - TReal x, y, z; + union { + struct { + TReal x, y, z; + }; + TReal v[ 3 ]; + }; } PACK_STRUCT; @@ -132,8 +139,12 @@ typedef aiVector3t aiVector3D; #else struct aiVector3D { - - float x,y,z; + union { + struct { + float x, y, z; + }; + float v[ 3 ]; + }; } PACK_STRUCT; #endif // __cplusplus diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index f06b077ff..0d0d62968 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -101,6 +101,14 @@ AI_FORCE_INLINE aiVector3t& aiVector3t::Normalize() { } // ------------------------------------------------------------------------------------------------ template +AI_FORCE_INLINE aiVector3t& aiVector3t::NormalizeSafe() { + TReal len = Length(); + if (len > static_cast(0)) + *this /= len; + return *this; +} +// ------------------------------------------------------------------------------------------------ +template AI_FORCE_INLINE const aiVector3t& aiVector3t::operator += (const aiVector3t& o) { x += o.x; y += o.y; z += o.z; return *this; } diff --git a/include/assimp/version.h b/include/assimp/version.h index 5502274c9..403798c1b 100644 --- a/include/assimp/version.h +++ b/include/assimp/version.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/port/AndroidJNI/AndroidJNIIOSystem.cpp b/port/AndroidJNI/AndroidJNIIOSystem.cpp index f9ba94cb1..43bb9213d 100644 --- a/port/AndroidJNI/AndroidJNIIOSystem.cpp +++ b/port/AndroidJNI/AndroidJNIIOSystem.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +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 +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 +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 +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. --------------------------------------------------------------------------- */ @@ -59,14 +59,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; // ------------------------------------------------------------------------------------------------ -// Constructor. +// Constructor. AndroidJNIIOSystem::AndroidJNIIOSystem(ANativeActivity* activity) { AndroidActivityInit(activity); } // ------------------------------------------------------------------------------------------------ -// Destructor. +// Destructor. AndroidJNIIOSystem::~AndroidJNIIOSystem() { // nothing to do here diff --git a/port/AndroidJNI/README.txt b/port/AndroidJNI/README.md similarity index 63% rename from port/AndroidJNI/README.txt rename to port/AndroidJNI/README.md index 337772025..570ca4fb3 100644 --- a/port/AndroidJNI/README.txt +++ b/port/AndroidJNI/README.md @@ -1,27 +1,25 @@ ---- Description --- - -This module provides a facade to io stream access to files -behind android asset manager within Android native application. +Build Asset Importer Lib for Android +==================================== +This module provides a fascade for the io-stream-access to files behind the +android-asset-management within an Android native application. - It is built as a static library - It requires Android NDK with android API > 9 support. ---- Building --- - +### Building ### To use this module please provide following cmake defines: - +``` -DASSIMP_ANDROID_JNIIOSYSTEM=ON -DCMAKE_TOOLCHAIN_FILE=$SOME_PATH/android.toolchain.cmake +``` "SOME_PATH" is a path to your cmake android toolchain script. ---- Code --- - +### Code ### +A small example how to wrap assimp for Android: +```cpp #include -... - Assimp::Importer* importer = new Assimp::Importer(); Assimp::AndroidJNIIOSystem* ioSystem = new Assimp::AndroidJNIIOSystem(app->activity); importer->SetIOHandler(ioSystem); - -... +``` diff --git a/port/jassimp/jassimp-native/src/jassimp.cpp b/port/jassimp/jassimp-native/src/jassimp.cpp index 8093db7ba..226e416aa 100644 --- a/port/jassimp/jassimp-native/src/jassimp.cpp +++ b/port/jassimp/jassimp-native/src/jassimp.cpp @@ -15,9 +15,32 @@ #define lprintf #endif +// Automatically deletes a local ref when it goes out of scope +class SmartLocalRef { +private: + JNIEnv* mJniEnv; + jobject& mJavaObj; + SmartLocalRef(const SmartLocalRef&); // non construction-copyable + SmartLocalRef& operator=(const SmartLocalRef&); // non copyable + +public: + template SmartLocalRef(JNIEnv* env, T& object) + : mJniEnv(env) + , mJavaObj((jobject&)object) + { + }; + + ~SmartLocalRef() { + if (mJavaObj != NULL) { + mJniEnv->DeleteLocalRef(mJavaObj); + } + } +}; + static bool createInstance(JNIEnv *env, const char* className, jobject& newInstance) { jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -34,7 +57,6 @@ static bool createInstance(JNIEnv *env, const char* className, jobject& newInsta } newInstance = env->NewObject(clazz, ctr_id); - env->DeleteLocalRef(clazz); if (NULL == newInstance) { @@ -49,6 +71,7 @@ static bool createInstance(JNIEnv *env, const char* className, jobject& newInsta static bool createInstance(JNIEnv *env, const char* className, const char* signature,/* const*/ jvalue* params, jobject& newInstance) { jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -65,7 +88,6 @@ static bool createInstance(JNIEnv *env, const char* className, const char* signa } newInstance = env->NewObjectA(clazz, ctr_id, params); - env->DeleteLocalRef(clazz); if (NULL == newInstance) { @@ -80,6 +102,7 @@ static bool createInstance(JNIEnv *env, const char* className, const char* signa static bool getField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject& field) { jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -88,7 +111,6 @@ static bool getField(JNIEnv *env, jobject object, const char* fieldName, const c } jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature); - env->DeleteLocalRef(clazz); if (NULL == fieldId) { @@ -105,6 +127,7 @@ static bool getField(JNIEnv *env, jobject object, const char* fieldName, const c static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint value) { jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -113,7 +136,6 @@ static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint } jfieldID fieldId = env->GetFieldID(clazz, fieldName, "I"); - env->DeleteLocalRef(clazz); if (NULL == fieldId) { @@ -130,6 +152,7 @@ static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jfloat value) { jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -138,7 +161,6 @@ static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jf } jfieldID fieldId = env->GetFieldID(clazz, fieldName, "F"); - env->DeleteLocalRef(clazz); if (NULL == fieldId) { @@ -155,6 +177,7 @@ static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jf static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject value) { jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -163,7 +186,6 @@ static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, c } jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature); - env->DeleteLocalRef(clazz); if (NULL == fieldId) { @@ -180,6 +202,7 @@ static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, c static bool getStaticField(JNIEnv *env, const char* className, const char* fieldName, const char* signature, jobject& field) { jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -205,6 +228,7 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char* const char* signature,/* const*/ jvalue* params) { jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -213,7 +237,6 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char* } jmethodID mid = env->GetMethodID(clazz, methodName, signature); - env->DeleteLocalRef(clazz); if (NULL == mid) { @@ -228,6 +251,7 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char* static bool callv(JNIEnv *env, jobject object, const char* typeName, const char* methodName, const char* signature,/* const*/ jvalue* params) { jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { lprintf("could not find class %s\n", typeName); @@ -235,7 +259,6 @@ static bool callv(JNIEnv *env, jobject object, const char* typeName, } jmethodID mid = env->GetMethodID(clazz, methodName, signature); - env->DeleteLocalRef(clazz); if (NULL == mid) { lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); @@ -252,6 +275,7 @@ static bool callStaticObject(JNIEnv *env, const char* typeName, const char* meth const char* signature,/* const*/ jvalue* params, jobject& returnValue) { jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); if (NULL == clazz) { @@ -276,6 +300,7 @@ static bool callStaticObject(JNIEnv *env, const char* typeName, const char* meth static bool copyBuffer(JNIEnv *env, jobject jMesh, const char* jBufferName, void* cData, size_t size) { jobject jBuffer = NULL; + SmartLocalRef bufferRef(env, jBuffer); if (!getField(env, jMesh, jBufferName, "Ljava/nio/ByteBuffer;", jBuffer)) { @@ -305,6 +330,7 @@ static bool copyBuffer(JNIEnv *env, jobject jMesh, const char* jBufferName, void static bool copyBufferArray(JNIEnv *env, jobject jMesh, const char* jBufferName, int index, void* cData, size_t size) { jobject jBufferArray = NULL; + SmartLocalRef bufferArrayRef(env, jBufferArray); if (!getField(env, jMesh, jBufferName, "[Ljava/nio/ByteBuffer;", jBufferArray)) { @@ -312,6 +338,7 @@ static bool copyBufferArray(JNIEnv *env, jobject jMesh, const char* jBufferName, } jobject jBuffer = env->GetObjectArrayElement((jobjectArray) jBufferArray, index); + SmartLocalRef bufferRef(env, jBuffer); if (env->GetDirectBufferCapacity(jBuffer) != size) { @@ -344,6 +371,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* create mesh */ jobject jMesh = NULL; + SmartLocalRef refMesh(env, jMesh); if (!createInstance(env, "jassimp/AiMesh", jMesh)) { @@ -353,6 +381,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add mesh to m_meshes java.util.List */ jobject jMeshes = NULL; + SmartLocalRef refMeshes(env, jMeshes); if (!getField(env, jScene, "m_meshes", "Ljava/util/List;", jMeshes)) { @@ -381,7 +410,9 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) return false; } - if (!setObjectField(env, jMesh, "m_name", "Ljava/lang/String;", env->NewStringUTF(cMesh->mName.C_Str()))) + jstring nameString = env->NewStringUTF(cMesh->mName.C_Str()); + SmartLocalRef refNameString(env, nameString); + if (!setObjectField(env, jMesh, "m_name", "Ljava/lang/String;", nameString)) { return false; } @@ -651,6 +682,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) aiBone *cBone = cMesh->mBones[b]; jobject jBone; + SmartLocalRef refBone(env, jBone); if (!createInstance(env, "jassimp/AiBone", jBone)) { return false; @@ -658,7 +690,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add bone to bone list */ jobject jBones = NULL; - + SmartLocalRef refBones(env, jBones); if (!getField(env, jMesh, "m_bones", "Ljava/util/List;", jBones)) { return false; @@ -672,7 +704,9 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) } /* set bone data */ - if (!setObjectField(env, jBone, "m_name", "Ljava/lang/String;", env->NewStringUTF(cBone->mName.C_Str()))) + jstring boneNameString = env->NewStringUTF(cBone->mName.C_Str()); + SmartLocalRef refNameString(env, boneNameString); + if (!setObjectField(env, jBone, "m_name", "Ljava/lang/String;", boneNameString)) { return false; } @@ -681,27 +715,29 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) for (unsigned int w = 0; w < cBone->mNumWeights; w++) { jobject jBoneWeight; - if (!createInstance(env, "jassimp/AiBoneWeight", jBoneWeight)) + SmartLocalRef refBoneWeight(env, jBoneWeight); + if (!createInstance(env, "jassimp/AiBoneWeight", jBoneWeight)) { return false; } /* add boneweight to bone list */ jobject jBoneWeights = NULL; - + SmartLocalRef refBoneWeights(env, jBoneWeights); if (!getField(env, jBone, "m_boneWeights", "Ljava/util/List;", jBoneWeights)) { return false; } - /* copy offset matrix */ jfloatArray jMatrixArr = env->NewFloatArray(16); + SmartLocalRef refMatrixArr(env, jMatrixArr); env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cBone->mOffsetMatrix); jvalue wrapParams[1]; wrapParams[0].l = jMatrixArr; jobject jMatrix; + SmartLocalRef refMatrix(env, jMatrix); if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix)) { @@ -733,8 +769,6 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) } } } - env->DeleteLocalRef(jMeshes); - env->DeleteLocalRef(jMesh); } return true; @@ -747,11 +781,13 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj /* wrap matrix */ jfloatArray jMatrixArr = env->NewFloatArray(16); + SmartLocalRef refMatrixArr(env, jMatrixArr); env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cNode->mTransformation); jvalue wrapMatParams[1]; wrapMatParams[0].l = jMatrixArr; jobject jMatrix; + SmartLocalRef refMatrix(env, jMatrix); if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix)) { @@ -761,6 +797,8 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj /* create mesh references array */ jintArray jMeshrefArr = env->NewIntArray(cNode->mNumMeshes); + SmartLocalRef refMeshrefArr(env, jMeshrefArr); + jint *temp = (jint*) malloc(sizeof(jint) * cNode->mNumMeshes); for (unsigned int i = 0; i < cNode->mNumMeshes; i++) @@ -774,7 +812,7 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj /* convert name */ jstring jNodeName = env->NewStringUTF(cNode->mName.C_Str()); - + SmartLocalRef refNodeName(env, jNodeName); /* wrap scene node */ jvalue wrapNodeParams[4]; @@ -802,6 +840,8 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj if (NULL != loadedNode) { *loadedNode = jNode; + } else { + env->DeleteLocalRef(jNode); } return true; @@ -815,6 +855,7 @@ static bool loadSceneGraph(JNIEnv *env, const aiScene* cScene, jobject& jScene) if (NULL != cScene->mRootNode) { jobject jRoot; + SmartLocalRef refRoot(env, jRoot); if (!loadSceneNode(env, cScene->mRootNode, NULL, &jRoot)) { @@ -842,6 +883,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) lprintf("converting material %d ...\n", m); jobject jMaterial = NULL; + SmartLocalRef refMaterial(env, jMaterial); if (!createInstance(env, "jassimp/AiMaterial", jMaterial)) { @@ -850,6 +892,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add material to m_materials java.util.List */ jobject jMaterials = NULL; + SmartLocalRef refMaterials(env, jMaterials); if (!getField(env, jScene, "m_materials", "Ljava/util/List;", jMaterials)) { @@ -894,9 +937,12 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) lprintf(" converting property %s ...\n", cProperty->mKey.C_Str()); jobject jProperty = NULL; + SmartLocalRef refProperty(env, jProperty); jvalue constructorParams[5]; - constructorParams[0].l = env->NewStringUTF(cProperty->mKey.C_Str()); + jstring keyString = env->NewStringUTF(cProperty->mKey.C_Str()); + SmartLocalRef refKeyString(env, keyString); + constructorParams[0].l = keyString; constructorParams[1].i = cProperty->mSemantic; constructorParams[2].i = cProperty->mIndex; constructorParams[3].i = cProperty->mType; @@ -908,6 +954,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) cProperty->mDataLength == 3 * sizeof(float)) { jobject jData = NULL; + SmartLocalRef refData(env, jData); /* wrap color */ jvalue wrapColorParams[3]; @@ -932,6 +979,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) cProperty->mDataLength == 4 * sizeof(float)) { jobject jData = NULL; + SmartLocalRef refData(env, jData); /* wrap color */ jvalue wrapColorParams[4]; @@ -954,6 +1002,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) else if (cProperty->mType == aiPTI_Float && cProperty->mDataLength == sizeof(float)) { jobject jData = NULL; + SmartLocalRef refData(env, jData); jvalue newFloatParams[1]; newFloatParams[0].f = ((float*) cProperty->mData)[0]; @@ -972,6 +1021,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) else if (cProperty->mType == aiPTI_Integer && cProperty->mDataLength == sizeof(int)) { jobject jData = NULL; + SmartLocalRef refData(env, jData); jvalue newIntParams[1]; newIntParams[0].i = ((int*) cProperty->mData)[0]; @@ -991,6 +1041,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) { /* skip length prefix */ jobject jData = env->NewStringUTF(cProperty->mData + 4); + SmartLocalRef refData(env, jData); constructorParams[4].l = jData; if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", @@ -1010,7 +1061,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) } jobject jBuffer = NULL; - + SmartLocalRef refBuffer(env, jBuffer); if (!getField(env, jProperty, "m_data", "Ljava/lang/Object;", jBuffer)) { return false; @@ -1036,7 +1087,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add property */ jobject jProperties = NULL; - + SmartLocalRef refProperties(env, jProperties); if (!getField(env, jMaterial, "m_properties", "Ljava/util/List;", jProperties)) { return false; @@ -1068,8 +1119,12 @@ static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene) lprintf(" converting animation %s ...\n", cAnimation->mName.C_Str()); jobject jAnimation; + SmartLocalRef refAnimation(env, jAnimation); + jvalue newAnimParams[3]; - newAnimParams[0].l = env->NewStringUTF(cAnimation->mName.C_Str()); + jstring nameString = env->NewStringUTF(cAnimation->mName.C_Str()); + SmartLocalRef refNameString(env, nameString); + newAnimParams[0].l = nameString; newAnimParams[1].d = cAnimation->mDuration; newAnimParams[2].d = cAnimation->mTicksPerSecond; @@ -1080,6 +1135,7 @@ static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add animation to m_animations java.util.List */ jobject jAnimations = NULL; + SmartLocalRef refAnimations(env, jAnimations); if (!getField(env, jScene, "m_animations", "Ljava/util/List;", jAnimations)) { @@ -1099,8 +1155,12 @@ static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene) const aiNodeAnim *cNodeAnim = cAnimation->mChannels[c]; jobject jNodeAnim; + SmartLocalRef refNodeAnim(env, jNodeAnim); + jvalue newNodeAnimParams[6]; - newNodeAnimParams[0].l = env->NewStringUTF(cNodeAnim->mNodeName.C_Str()); + jstring animationName = env->NewStringUTF(cNodeAnim->mNodeName.C_Str()); + SmartLocalRef refAnimationName(env, animationName); + newNodeAnimParams[0].l = animationName; newNodeAnimParams[1].i = cNodeAnim->mNumPositionKeys; newNodeAnimParams[2].i = cNodeAnim->mNumRotationKeys; newNodeAnimParams[3].i = cNodeAnim->mNumScalingKeys; @@ -1115,6 +1175,7 @@ static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add nodeanim to m_animations java.util.List */ jobject jNodeAnims = NULL; + SmartLocalRef refNodeAnims(env, jNodeAnims); if (!getField(env, jAnimation, "m_nodeAnims", "Ljava/util/List;", jNodeAnims)) { @@ -1171,6 +1232,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapColorParams[1].f = cLight->mColorDiffuse.g; wrapColorParams[2].f = cLight->mColorDiffuse.b; jobject jDiffuse; + SmartLocalRef refDiffuse(env, jDiffuse); if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse)) { return false; @@ -1180,6 +1242,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapColorParams[1].f = cLight->mColorSpecular.g; wrapColorParams[2].f = cLight->mColorSpecular.b; jobject jSpecular; + SmartLocalRef refSpecular(env, jSpecular); if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular)) { return false; @@ -1189,6 +1252,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapColorParams[1].f = cLight->mColorAmbient.g; wrapColorParams[2].f = cLight->mColorAmbient.b; jobject jAmbient; + SmartLocalRef refAmbient(env, jAmbient); if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient)) { return false; @@ -1201,6 +1265,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapVec3Params[1].f = cLight->mPosition.y; wrapVec3Params[2].f = cLight->mPosition.z; jobject jPosition; + SmartLocalRef refPosition(env, jPosition); if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition)) { return false; @@ -1210,6 +1275,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapVec3Params[1].f = cLight->mPosition.y; wrapVec3Params[2].f = cLight->mPosition.z; jobject jDirection; + SmartLocalRef refDirection(env, jDirection); if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection)) { return false; @@ -1217,9 +1283,11 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) jobject jLight; - + SmartLocalRef refLight(env, jLight); jvalue params[12]; - params[0].l = env->NewStringUTF(cLight->mName.C_Str());; + jstring lightName = env->NewStringUTF(cLight->mName.C_Str()); + SmartLocalRef refLightName(env, lightName); + params[0].l = lightName; params[1].i = cLight->mType; params[2].l = jPosition; params[3].l = jDirection; @@ -1240,6 +1308,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add light to m_lights java.util.List */ jobject jLights = NULL; + SmartLocalRef refLights(env, jLights); if (!getField(env, jScene, "m_lights", "Ljava/util/List;", jLights)) { @@ -1276,6 +1345,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapPositionParams[1].f = cCamera->mPosition.y; wrapPositionParams[2].f = cCamera->mPosition.z; jobject jPosition; + SmartLocalRef refPosition(env, jPosition); if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition)) { return false; @@ -1285,6 +1355,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapPositionParams[1].f = cCamera->mUp.y; wrapPositionParams[2].f = cCamera->mUp.z; jobject jUp; + SmartLocalRef refUp(env, jUp); if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp)) { return false; @@ -1294,6 +1365,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) wrapPositionParams[1].f = cCamera->mLookAt.y; wrapPositionParams[2].f = cCamera->mLookAt.z; jobject jLookAt; + SmartLocalRef refLookAt(env, jLookAt); if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt)) { return false; @@ -1301,9 +1373,12 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) jobject jCamera; + SmartLocalRef refCamera(env, jCamera); jvalue params[8]; - params[0].l = env->NewStringUTF(cCamera->mName.C_Str()); + jstring cameraName = env->NewStringUTF(cCamera->mName.C_Str()); + SmartLocalRef refCameraName(env, cameraName); + params[0].l = cameraName; params[1].l = jPosition; params[2].l = jUp; params[3].l = jLookAt; @@ -1320,7 +1395,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) /* add camera to m_cameras java.util.List */ jobject jCameras = NULL; - + SmartLocalRef refCameras(env, jCameras); if (!getField(env, jScene, "m_cameras", "Ljava/util/List;", jCameras)) { return false; diff --git a/port/jassimp/jassimp/src/jassimp/AiLightType.java b/port/jassimp/jassimp/src/jassimp/AiLightType.java index 5df38763c..ec3c39b02 100644 --- a/port/jassimp/jassimp/src/jassimp/AiLightType.java +++ b/port/jassimp/jassimp/src/jassimp/AiLightType.java @@ -70,9 +70,20 @@ public enum AiLightType { * direction it is pointing to. A good example for a spot light is a light * spot in sport arenas. */ - SPOT(0x3); + SPOT(0x3), + + + /** + * The generic light level of the world, including the bounces of all other + * lightsources.

+ * + * Typically, there's at most one ambient light in a scene. + * This light type doesn't have a valid position, direction, or + * other properties, just a color. + */ + AMBIENT(0x4); + - /** * Utility method for converting from c/c++ based integer enums to java * enums.

diff --git a/scripts/appveyor/compiler_setup.bat b/scripts/appveyor/compiler_setup.bat new file mode 100644 index 000000000..7d4851493 --- /dev/null +++ b/scripts/appveyor/compiler_setup.bat @@ -0,0 +1,36 @@ +rem @echo off + +:: Now we declare a scope +Setlocal EnableDelayedExpansion EnableExtensions + +if not defined Configuration set Configuration=14 2015 + +if "%Configuration%"=="MinGW" ( goto :mingw ) + +set arch=x86 + +if "%platform%" EQU "x64" ( set arch=x86_amd64 ) + +if "%Configuration%"=="14 2015" ( + set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" +) + +if "%Configuration%"=="12 2013" ( + set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" +) + +if "%Configuration%"=="11 2012" ( + set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" +) + +if "%Configuration%"=="10 2010" ( + set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" +) + +:: Visual Studio detected +endlocal & call %SET_VS_ENV% %arch% +goto :eof + +:: MinGW detected +:mingw +endlocal & set PATH=c:\mingw\bin;%PATH% diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d3bd490e8..f30172a30 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,6 +28,7 @@ SET( TEST_SRCS unit/utJoinVertices.cpp unit/utLimitBoneWeights.cpp unit/utMaterialSystem.cpp + unit/utMatrix4x4.cpp unit/utPretransformVertices.cpp unit/utRemoveComments.cpp unit/utRemoveComponent.cpp @@ -43,26 +44,27 @@ SET( TEST_SRCS unit/utNoBoostTest.cpp unit/utColladaExportCamera.cpp unit/utColladaExportLight.cpp + unit/utIssues.cpp ) SOURCE_GROUP( tests FILES ${TEST_SRCS} ) if(AddGTest_FOUND) -add_executable( unit - unit/CCompilerTest.c - unit/Main.cpp - ../code/Version.cpp - ${TEST_SRCS} -) + add_executable( unit + unit/CCompilerTest.c + unit/Main.cpp + ../code/Version.cpp + ${TEST_SRCS} + ) -add_definitions(-DASSIMP_TEST_MODELS_DIR="${CMAKE_CURRENT_LIST_DIR}/models") + add_definitions(-DASSIMP_TEST_MODELS_DIR="${CMAKE_CURRENT_LIST_DIR}/models") -SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} ) + SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} ) -add_dependencies( unit gtest ) -target_link_libraries( unit assimp - debug ${GTEST_DEBUG_LIBRARIES} - optimized ${GTEST_RELEASE_LIBRARIES} -) + add_dependencies( unit gtest ) + target_link_libraries( unit assimp + debug ${GTEST_DEBUG_LIBRARIES} + optimized ${GTEST_RELEASE_LIBRARIES} + ) endif(AddGTest_FOUND) add_subdirectory(headercheck) diff --git a/test/models/Collada/library_animation_clips.dae b/test/models/Collada/library_animation_clips.dae new file mode 100644 index 000000000..ee793389b --- /dev/null +++ b/test/models/Collada/library_animation_clips.dae @@ -0,0 +1,623 @@ + + + + + Anonymous + Collada Exporter for Blender 2.6+, by Juan Linietsky (juan@codenix.com) + + 2016-02-04T00:44:39Z + 2016-02-04T00:44:39Z + + Z_UP + + + + + + + + + + 0.0 0.0 0.0 1.0 + + + 0.0 0.0 0.0 1.0 + + + 0.6400000190734865 0.6400000190734865 0.6400000190734865 1.0 + + + 0.5 0.5 0.5 1.0 + + + 50 + + + 1.0 1.0 1.0 1.0 + + + 4.0 + + + + + + + 0 + + + + + + + + + + + + + + + + 1.0 0.9999999403953552 -1.0 1.0 -1.0 -1.0 -1.0000001192092896 -0.9999998211860657 -1.0 -0.9999996423721313 1.0000003576278687 -1.0 -0.9999999403953552 1.0 1.0 -1.0000003576278687 -0.9999996423721313 1.0 -1.0000003576278687 -0.9999996423721313 3.0 -0.9999999403953552 1.0 3.0 1.0 0.9999999403953552 -1.0 1.0000004768371582 0.999999463558197 1.0 0.9999993443489075 -1.0000005960464478 1.0 1.0 -1.0 -1.0 1.0 -1.0 -1.0 0.9999993443489075 -1.0000005960464478 1.0 -1.0000003576278687 -0.9999996423721313 1.0 -1.0000001192092896 -0.9999998211860657 -1.0 -1.0000001192092896 -0.9999998211860657 -1.0 -0.9999996423721313 1.0000003576278687 -1.0 1.0000004768371582 0.999999463558197 1.0 1.0 0.9999999403953552 -1.0 -0.9999996423721313 1.0000003576278687 -1.0 -0.9999999403953552 1.0 1.0 -0.9545343518257141 -0.9545336365699768 4.598935604095459 -0.9545339345932007 0.9545340538024902 4.598935604095459 0.9999993443489075 -1.0000005960464478 3.0 -1.0000003576278687 -0.9999996423721313 3.0 -0.9999999403953552 1.0 3.0 1.0000004768371582 0.999999463558197 3.0 1.0000004768371582 0.999999463558197 3.0 0.9999993443489075 -1.0000005960464478 3.0 -0.9025039672851562 0.9025040864944458 6.0 -0.9025043845176697 -0.9025037288665771 6.0 -0.8504744172096252 -0.8504738211631775 7.0 -0.8504740595817566 0.8504741191864014 7.0 0.9545333385467529 -0.954534649848938 4.598935604095459 -0.9545343518257141 -0.9545336365699768 4.598935604095459 -0.9545339345932007 0.9545340538024902 4.598935604095459 0.9545344710350037 0.9545334577560425 4.598935604095459 0.9545344710350037 0.9545334577560425 4.598935604095459 0.9545333385467529 -0.954534649848938 4.598935604095459 0.8504745364189148 0.8504736423492432 7.0 -0.8504740595817566 0.8504741191864014 7.0 -0.8504744172096252 -0.8504738211631775 7.0 0.8504735231399536 -0.8504747152328491 7.0 -0.9025043845176697 -0.9025037288665771 6.0 0.9025034308433533 -0.9025046825408936 6.0 0.8504735231399536 -0.8504747152328491 7.0 -0.8504744172096252 -0.8504738211631775 7.0 0.9025045037269592 0.9025035500526428 6.0 -0.9025039672851562 0.9025040864944458 6.0 -0.8504740595817566 0.8504741191864014 7.0 0.8504745364189148 0.8504736423492432 7.0 0.9025034308433533 -0.9025046825408936 6.0 0.9025045037269592 0.9025035500526428 6.0 0.8504745364189148 0.8504736423492432 7.0 0.8504735231399536 -0.8504747152328491 7.0 -0.9025039672851562 0.9025040864944458 6.0 0.9025045037269592 0.9025035500526428 6.0 0.9025050401687622 2.9289722442626953 6.009448051452637 -0.9025033712387085 2.9289727210998535 6.009448051452637 0.9545350074768066 2.925309658050537 4.607422351837158 -0.9545333385467529 2.9253101348876953 4.607422351837158 -0.9025033712387085 2.9289727210998535 6.009448051452637 0.9025050401687622 2.9289722442626953 6.009448051452637 -0.9025033712387085 2.9289727210998535 6.009448051452637 -0.9545333385467529 2.9253101348876953 4.607422351837158 0.9545344710350037 0.9545334577560425 4.598935604095459 -0.9545339345932007 0.9545340538024902 4.598935604095459 -0.9545333385467529 2.9253101348876953 4.607422351837158 0.9545350074768066 2.925309658050537 4.607422351837158 0.9545350074768066 2.925309658050537 4.607422351837158 0.9025050401687622 2.9289722442626953 6.009448051452637 + + + + + + + + + + 0.0 0.0 -1.0 0.0 0.0 -1.0 0.0 0.0 -1.0 0.0 0.0 -1.0 -0.9999999403953552 2.2351740369686013e-07 -6.70552182668871e-08 -1.0 2.2351743211856956e-07 -6.70552182668871e-08 -0.9999008774757385 2.1862656751636678e-07 0.01408354565501213 -0.9999008774757385 2.1862656751636678e-07 0.01408354565501213 1.0 -2.980232238769531e-07 4.470339831641468e-08 0.9999999403953552 -4.321336461998726e-07 2.2351700934564178e-08 1.0 -4.3213370304329146e-07 2.235169560549366e-08 1.0 -2.980232238769531e-07 4.470339831641468e-08 -2.831220911048149e-07 -1.0 -1.7881397695873602e-07 -3.7997961044311523e-07 -0.9999999403953552 -8.940698847936801e-08 -3.799796957082435e-07 -1.0 -8.940698847936801e-08 -2.831220911048149e-07 -1.0 -1.7881397695873602e-07 -1.0 2.384185791015625e-07 -1.341104365337742e-07 -1.0 2.384185791015625e-07 -1.341104365337742e-07 2.533197118737007e-07 1.0 8.195638656616211e-08 2.384185791015625e-07 1.0 1.6391278734317893e-07 2.384185791015625e-07 1.0 1.6391278734317893e-07 2.533197118737007e-07 1.0 8.195638656616211e-08 -0.9994659423828125 2.2885373596182035e-07 0.03267655521631241 -0.9994159936904907 -5.6084059906424955e-05 0.03417250141501427 -4.903030230707373e-07 -0.999900758266449 0.014083554036915302 -4.903030230707373e-07 -0.999900758266449 0.014083554036915302 2.793038049730967e-07 0.9999008774757385 0.014083568938076496 2.793038049730967e-07 0.9999008774757385 0.014083568938076496 0.9999008774757385 -5.880169169358851e-07 0.014083541929721832 0.9999008774757385 -5.880169169358851e-07 0.014083541929721832 -0.9991201162338257 -5.4629024816676974e-05 0.041940946131944656 -0.9990172386169434 2.1669733030194038e-07 0.044324908405542374 -0.9986491799354553 2.0373587972244422e-07 0.05195961520075798 -0.9986491799354553 2.0373587972244422e-07 0.05195961520075798 -5.205995421420084e-07 -0.9994659423828125 0.0326765701174736 -5.205994852985896e-07 -0.9994659423828125 0.032676566392183304 2.9053398975520395e-07 0.9995959997177124 0.02842373587191105 2.9053398975520395e-07 0.9995959997177124 0.02842373587191105 0.9994159936904907 -5.6835739087546244e-05 0.03417249023914337 0.9994659423828125 -6.028049028827809e-07 0.032676540315151215 5.150363904249389e-07 0.0 1.0 5.150363904249389e-07 0.0 1.0 5.150363904249389e-07 0.0 1.0 5.150363904249389e-07 0.0 1.0 -5.323321374817169e-07 -0.9990172386169434 0.04432494565844536 -5.323321374817169e-07 -0.9990172386169434 0.04432494565844536 -5.263181037662434e-07 -0.9986491203308105 0.05195968598127365 -5.263181037662434e-07 -0.9986491203308105 0.05195968598127365 2.886259267143032e-07 0.9986491203308105 0.05195966362953186 2.886259267143032e-07 0.9986491203308105 0.05195966362953186 2.886259267143032e-07 0.9986491203308105 0.05195966362953186 2.886259267143032e-07 0.9986491203308105 0.05195966362953186 0.9990172386169434 -6.030014674252016e-07 0.04432491585612297 0.9991201162338257 -5.53747704543639e-05 0.04194095358252525 0.9986491799354553 -6.112079518061364e-07 0.051959652453660965 0.9986491799354553 -6.112079518061364e-07 0.051959652453660965 -1.2316533348766256e-09 -0.0046622720547020435 0.9999890923500061 -1.2316533348766256e-09 -0.0046622720547020435 0.9999890923500061 -1.2316533348766256e-09 -0.0046622720547020435 0.9999890923500061 -1.2316533348766256e-09 -0.0046622720547020435 0.9999890923500061 2.564144381267397e-07 0.9999966025352478 -0.0026121772825717926 2.564144381267397e-07 0.9999966025352478 -0.0026121772825717926 2.564144381267397e-07 0.9999966025352478 -0.0026121772825717926 2.564144381267397e-07 0.9999966025352478 -0.0026121772825717926 -0.9993117451667786 -0.00016610079910606146 0.03709486126899719 -0.9993117451667786 -0.00016610079910606146 0.03709486126899719 7.69835608593894e-08 0.004306257236748934 -0.999990701675415 7.69835608593894e-08 0.004306257236748934 -0.999990701675415 7.69835608593894e-08 0.004306257236748934 -0.999990701675415 7.69835608593894e-08 0.004306257236748934 -0.999990701675415 0.9993118047714233 -0.00016669620526954532 0.03709486499428749 0.9993118047714233 -0.00016669620526954532 0.03709486499428749 + + + + + + + + + + 0.853708028793335 0.1462918519973755 0.853708028793335 0.00016813237743917853 0.9998317956924438 0.00016813237743917853 0.9998317360877991 0.1462918221950531 0.41687875986099243 0.15038259327411652 0.5629437565803528 0.14623311161994934 0.5670932531356812 0.29229798913002014 0.42102837562561035 0.29644766449928284 0.1580430120229721 0.005586783867329359 0.15262427926063538 0.1516100913286209 0.006601004861295223 0.14619146287441254 0.012019664980471134 0.00016813237743917853 0.7135531306266785 0.00016813237743917853 0.7135540843009949 0.14629174768924713 0.5674304366111755 0.1462927609682083 0.5674294829368591 0.0001691012439550832 0.5587943196296692 0.00016813237743917853 0.4127293825149536 0.0043175434693694115 0.853708028793335 0.2924155592918396 0.853708028793335 0.1462918519973755 0.9998317360877991 0.1462918221950531 0.9998318552970886 0.2924154996871948 0.5670915842056274 0.4092135429382324 0.42766785621643066 0.41317465901374817 0.713555097579956 0.2924153804779053 0.5674314498901367 0.29241642355918884 0.9998318552970886 0.43853920698165894 0.8537081480026245 0.4385392665863037 0.14720562100410461 0.29763343930244446 0.0011823981767520308 0.29221469163894653 0.43437695503234863 0.5154602527618408 0.5662007331848145 0.5117148756980896 0.5644786357879639 0.5849537253379822 0.44025471806526184 0.5884833335876465 0.7102342247962952 0.4092837870121002 0.5707541108131409 0.4092848598957062 0.9965101480484009 0.5554076433181763 0.8570300936698914 0.555407702922821 0.13955222070217133 0.4142983853816986 0.00016813237743917853 0.40912580490112305 0.7214940786361694 0.46781307458877563 0.8457685708999634 0.46781307458877563 0.8457684516906738 0.5920873880386353 0.7214942574501038 0.5920873880386353 0.5745562314987183 0.5117197632789612 0.7064335942268372 0.51171875 0.7026327252388 0.5848795175552368 0.5783581733703613 0.584880530834198 0.7176926732063293 0.39465245604515076 0.8495699167251587 0.39465245604515076 0.8457685708999634 0.46781307458877563 0.7214940786361694 0.46781307458877563 0.00016824003250803798 0.5116311311721802 0.13195458054542542 0.5165219306945801 0.12544254958629608 0.5894912481307983 0.0012538435403257608 0.5848821997642517 0.8495699167251587 0.39465245604515076 0.7176926732063293 0.39465245604515076 0.7176927328109741 0.24659334123134613 0.8495699763298035 0.2465934455394745 0.7138913869857788 0.1441582441329956 0.8533715605735779 0.14415842294692993 0.8495699763298035 0.2465934455394745 0.7176927328109741 0.24659334123134613 0.28639882802963257 0.520354688167572 0.2837550938129425 0.4178834557533264 0.7138914465904236 0.00016813237743917853 0.8533717393875122 0.00016831178800202906 0.8533715605735779 0.14415842294692993 0.7138913869857788 0.1441582441329956 0.28341880440711975 0.4202575087547302 0.2798847556114197 0.5227020382881165 + + + + + + + + + 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 + + + + + + + + + + + + + + + + +

0 1 2 3

+

4 5 6 7

+

8 9 10 11

+

12 13 14 15

+

16 5 4 17

+

18 19 20 21

+

7 6 22 23

+

14 13 24 25

+

18 21 26 27

+

10 9 28 29

+

30 31 32 33

+

25 24 34 35

+

27 26 36 37

+

29 28 38 39

+

40 41 42 43

+

44 45 46 47

+

48 49 50 51

+

52 53 54 55

+

23 22 31 30

+

35 34 45 44

+

56 57 58 59

+

39 38 53 52

+

60 61 62 63

+

23 30 64 65

+

66 67 68 69

+

53 38 70 71

+ + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + id-skelbones-2-0 id-skelbones-2-1 id-skelbones-2-2 id-skelbones-2-3 id-skelbones-2-4 + + + + + + + + 1.0 -0.0 0.0 -0.0 -0.0 7.549790126404332e-08 1.0 1.0 0.0 -1.0 7.549790126404332e-08 7.549790126404332e-08 -0.0 0.0 -0.0 1.0 1.0 -0.0 0.0 -0.0 -0.0 7.549790126404332e-08 1.0 -1.0 0.0 -1.0 7.549790126404332e-08 7.549790126404332e-08 -0.0 0.0 -0.0 1.0 1.0 3.019916050561733e-07 0.0 -9.11989328999073e-14 -2.2799733224976824e-14 7.549790126404332e-08 1.0 -3.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 7.549789415861596e-08 -0.0 0.0 -0.0 1.0 1.0 -0.0 -0.0 4.559946644995365e-14 -0.0 7.549790126404332e-08 1.0 -5.0 0.0 -1.0 7.549790126404332e-08 7.54979225803254e-08 -0.0 0.0 -0.0 1.0 1.0 -0.0 1.6940658945086007e-21 4.559945628555828e-14 -0.0 1.0 -0.0 -4.5298742179511464e-07 5.621949100372871e-15 -0.0 1.0 -5.0 -0.0 0.0 -0.0 1.0 + + + + + + + + 1.0 1.0 1.0 1.0 0.9710749387741089 1.0 0.5 0.5 0.4995494484901428 0.5004505515098572 1.0 0.9998676180839539 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.9998676180839539 1.0 1.0 0.9710749387741089 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.4995494484901428 0.5004505515098572 0.5 0.5 0.5 0.5 0.5 0.5 0.3333333432674408 0.6666666865348816 0.6666666865348816 0.3333333432674408 1.0 1.0 0.4999999403953552 0.5000000596046448 0.5 0.5 0.5 0.5 0.49981489777565 0.5001850128173828 0.49981489777565 0.5001850128173828 0.4999999403953552 0.5000000596046448 0.999976634979248 1.0 1.0 1.0 0.6666666865348816 0.3333333432674408 0.6666667461395264 0.333333283662796 1.0 1.0 0.33317145705223083 0.6668285131454468 0.3333333432674408 0.6666666865348816 1.0 0.999976634979248 0.6666667461395264 0.333333283662796 0.33317145705223083 0.6668285131454468 0.999976634979248 1.0 0.3333333432674408 0.6666666865348816 0.33317145705223083 0.6668285131454468 0.33317145705223083 0.6668285131454468 0.3333333432674408 0.6666666865348816 0.49981483817100525 0.5001851320266724 0.5 0.5 0.3333333432674408 0.6666666865348816 0.33317145705223083 0.6668285131454468 0.3333333432674408 0.6666666865348816 0.5 0.5 0.49981489777565 0.5001850128173828 0.5 0.5 0.5 0.5 0.49981483817100525 0.5001851320266724 0.49981483817100525 0.5001851320266724 0.33317145705223083 0.6668285131454468 + + + + + + + + + + + + + + 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 2 2 2 1 1 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + 0 0 0 1 0 2 0 3 1 4 1 5 1 6 2 7 1 8 2 9 0 10 1 11 1 12 0 13 0 14 1 15 1 16 0 17 0 18 0 19 1 20 0 21 0 22 1 23 2 24 3 25 2 26 3 27 1 28 2 29 1 30 2 31 1 32 2 33 1 34 2 35 1 36 2 37 1 38 2 39 2 40 3 41 3 42 2 43 3 44 3 45 2 46 3 47 2 48 3 49 2 50 3 51 2 52 3 53 2 54 3 55 2 56 3 57 3 58 3 59 3 60 3 61 3 62 2 63 3 64 2 65 3 66 3 67 2 68 3 69 2 70 3 71 3 72 3 73 3 74 2 75 2 76 3 77 3 78 3 79 2 80 3 81 2 82 3 83 2 84 3 85 2 86 3 87 2 88 3 89 2 90 3 91 2 92 3 93 2 94 3 95 2 96 3 97 2 98 3 99 2 100 3 101 2 102 3 103 2 104 3 105 2 106 3 107 2 108 3 109 2 110 3 111 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 -1.0 0.0 0.0 0.0 1.0 + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + 1.0 -2.2799733224976824e-14 3.019916050561733e-07 0.0 2.2799733224976824e-14 1.0 0.0 2.0 -3.019916050561733e-07 0.0 1.0 7.105427357601002e-15 0.0 0.0 0.0 1.0 + + 1.0 2.2799733224976824e-14 -3.019916050561733e-07 -3.3881317890172014e-21 -2.2799733224976824e-14 1.0 0.0 2.0 3.019916050561733e-07 0.0 1.0 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 + + + 1.0 3.019916050561733e-07 -1.6940658945086007e-21 -3.3881317890172014e-21 -2.8421682325349695e-14 7.549790126404332e-08 1.0 2.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + #id-bone-3 + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 3.019916050561733e-07 -1.6940658945086007e-21 -3.3881317890172014e-21 -2.8421682325349695e-14 7.549790126404332e-08 1.0 2.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 1.0 3.0198953027138487e-07 -1.5963781407890565e-09 4.261721642251359e-09 -2.1282611228912174e-09 7.553694558737334e-08 1.0 1.9999998807907104 3.0198589229257777e-07 -1.0 7.570474735985044e-08 4.5565684558823705e-10 0.0 0.0 0.0 1.0 1.0 3.019813448190689e-07 -4.2969077185261995e-09 -2.3610937205376104e-08 -7.037897375994362e-09 7.6121068559587e-08 1.0 2.000000238418579 3.0177761800587177e-07 -1.0 7.702328730374575e-08 7.712515071034431e-09 0.0 0.0 0.0 1.0 1.0 3.0174851417541504e-07 -9.467839845456183e-09 4.011599230580032e-08 -1.7462298274040222e-10 7.724156603217125e-08 1.0000001192092896 2.000000238418579 3.019813448190689e-07 -1.0 7.700873538851738e-08 -1.6298145055770874e-09 0.0 0.0 0.0 1.0 0.9999998807907104 3.026798367500305e-07 8.192728273570538e-09 1.9393337424844503e-07 -3.0253431759774685e-08 7.59027898311615e-08 0.9999998807907104 1.9999990463256836 3.022141754627228e-07 -0.9999999403953552 7.613562047481537e-08 -1.7695128917694092e-08 0.0 0.0 0.0 1.0 1.0 3.012828528881073e-07 6.184563972055912e-09 2.486049197614193e-07 5.3958501666784286e-08 7.82310962677002e-08 1.0 1.9999995231628418 3.022141754627228e-07 -1.0 7.543712854385376e-08 -5.587935447692871e-09 0.0 0.0 0.0 1.0 1.0 3.050081431865692e-07 -1.2660166248679161e-08 -3.2654497772455215e-07 2.240994945168495e-09 7.264316082000732e-08 0.9999999403953552 1.999999761581421 3.012828528881073e-07 -0.9999999403953552 7.264316082000732e-08 1.1175870895385742e-08 0.0 0.0 0.0 1.0 1.0 3.026798367500305e-07 1.8044374883174896e-09 4.7672074288129807e-07 -4.5372871682047844e-08 6.891787052154541e-08 1.0000001192092896 2.000000238418579 3.0174851417541504e-07 -1.0 7.636845111846924e-08 0.0 0.0 0.0 0.0 1.0 1.0 3.0174851417541504e-07 -1.949956640601158e-08 -3.995373845100403e-07 -9.167706593871117e-09 7.82310962677002e-08 1.0 2.000000238418579 3.022141754627228e-07 -1.0 7.078051567077637e-08 -1.4901161193847656e-08 0.0 0.0 0.0 1.0 1.0 2.9546208679676056e-07 2.4141627363860607e-08 2.2811582311987877e-07 3.8853613659739494e-09 6.705522537231445e-08 1.0 2.000000238418579 3.0151568353176117e-07 -1.0000001192092896 7.450580596923828e-08 -1.4901161193847656e-08 0.0 0.0 0.0 1.0 1.0 3.0384398996829987e-07 -1.0943040251731873e-08 -2.1746382117271423e-07 -2.8172507882118225e-08 7.695052772760391e-08 1.000000238418579 2.000000476837158 2.9779039323329926e-07 -1.0000001192092896 7.566995918750763e-08 -1.862645149230957e-09 0.0 0.0 0.0 1.0 0.9999999403953552 3.0547380447387695e-07 -5.3551048040390015e-09 -3.5390257835388184e-08 -8.614733815193176e-09 8.009374141693115e-08 0.9999998807907104 1.9999996423721313 2.980232238769531e-07 -0.9999998807907104 8.195638656616211e-08 2.9802322387695312e-08 0.0 0.0 0.0 1.0 1.0 3.026798367500305e-07 9.19681042432785e-09 3.296881914138794e-07 -3.655441105365753e-08 7.729977369308472e-08 0.9999999403953552 1.999999761581421 3.129243850708008e-07 -0.9999999403953552 7.636845111846924e-08 1.4901161193847656e-08 0.0 0.0 0.0 1.0 1.0 2.975575625896454e-07 8.381903171539307e-09 1.1548399925231934e-07 1.1175870895385742e-08 7.636845111846924e-08 1.0 2.000000476837158 3.0314549803733826e-07 -1.0 7.636845111846924e-08 1.4901161193847656e-08 0.0 0.0 0.0 1.0 1.0 3.03611159324646e-07 -2.7939677238464355e-09 3.725290298461914e-09 8.381903171539307e-09 7.450580596923828e-08 1.0 2.000000476837158 2.905726432800293e-07 -1.0 7.450580596923828e-08 1.4901161193847656e-08 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.99998539686203 0.005406782031059265 2.0841630504753184e-11 0.0 -0.005406782031059265 0.99998539686203 -5.684341886080802e-14 2.0 -2.0841633974200136e-11 -5.684341886080802e-14 1.0 0.0 0.0 0.0 0.0 1.0 0.9996087551116943 0.02796982228755951 1.4218640154162188e-10 0.0 -0.02796982228755951 0.9996087551116943 -1.9895196601282805e-12 2.0 -1.4218648480834872e-10 -1.9895196601282805e-12 1.0 0.0 0.0 0.0 0.0 1.0 0.998104453086853 0.06154264137148857 4.495371852542007e-10 0.0 -0.06154264137148857 0.998104453086853 -1.3848477919964353e-11 2.0 -4.495372962765032e-10 -1.3848477919964353e-11 1.0 3.552713678800501e-15 0.0 0.0 0.0 1.0 0.9950810074806213 0.09906430542469025 1.1069893890436333e-09 0.0 -0.09906430542469025 0.9950810074806213 -5.496758603840135e-11 2.0 -1.1069891669990284e-09 -5.496758603840135e-11 1.0 1.1546319456101628e-14 0.0 0.0 0.0 1.0 0.9903477430343628 0.1386050283908844 2.387212427734653e-09 0.0 -0.1386050283908844 0.9903477430343628 -1.6624568388579064e-10 1.9999998807907104 -2.387212205690048e-09 -1.6623857845843304e-10 1.0 -1.4210854715202004e-14 0.0 0.0 0.0 1.0 0.9839622974395752 0.1783764809370041 4.3626333656732186e-09 0.0 -0.1783764809370041 0.9839622974395752 -3.922409064216481e-10 2.000000238418579 -4.362632921584009e-09 -3.922409064216481e-10 1.0 1.4210854715202004e-14 0.0 0.0 0.0 1.0 0.9762129187583923 0.21681401133537292 7.393061718374838e-09 0.0 -0.21681401133537292 0.9762129187583923 -8.111058491522272e-10 2.0 -7.393062162464048e-09 -8.111058491522272e-10 1.0 0.0 0.0 0.0 0.0 1.0 0.9676145911216736 0.2524321675300598 1.2406852434310167e-08 0.0 -0.2524321675300598 0.9676145911216736 -1.5917152040856308e-09 2.0 -1.2406852434310167e-08 -1.5917152040856308e-09 1.0 -1.4210854715202004e-14 0.0 0.0 0.0 1.0 0.9592233300209045 0.28264933824539185 2.133943155513407e-08 0.0 -0.28264933824539185 0.9592233300209045 -3.078554300373071e-09 2.0 -2.133943155513407e-08 -3.078554300373071e-09 1.0 -1.4210854715202004e-14 0.0 0.0 0.0 1.0 0.950993537902832 0.3092101812362671 0.0005914760404266417 4.874891601502895e-09 -0.30921056866645813 0.9509932994842529 0.000737061258405447 2.000000238418579 -0.0003345829900354147 -0.0008838316425681114 0.9999995827674866 -1.0477378964424133e-09 0.0 0.0 0.0 1.0 0.9428225159645081 0.333288311958313 0.002140357159078121 6.129266694188118e-08 -0.33329325914382935 0.9428195953369141 0.002598921302706003 2.0 -0.0011517815291881561 -0.003163686953485012 0.9999943375587463 -9.313225746154785e-10 0.0 0.0 0.0 1.0 0.9348953366279602 0.3548996150493622 0.00411301851272583 3.3527612686157227e-08 -0.35491713881492615 0.9348850250244141 0.004878699779510498 2.0 -0.00211375136859715 -0.006020858883857727 0.9999796152114868 -4.6566128730773926e-09 0.0 0.0 0.0 1.0 0.9280365705490112 0.37244030833244324 0.006034713238477707 1.1874362826347351e-08 -0.3724772334098816 0.9280148148536682 0.007022818550467491 2.0 -0.0029847193509340286 -0.008765213191509247 0.9999571442604065 1.4901161193847656e-08 0.0 0.0 0.0 1.0 0.9249669909477234 0.3799836039543152 0.006962517276406288 -5.052424967288971e-08 -0.38003233075141907 0.9249383211135864 0.008036060258746147 2.0 -0.003386327065527439 -0.010079077444970608 0.9999434947967529 7.450580596923828e-09 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 -2.2799733224976824e-14 3.019916050561733e-07 0.0 2.2799733224976824e-14 1.0 0.0 2.0 -3.019916050561733e-07 0.0 1.0 7.105427357601002e-15 0.0 0.0 0.0 1.0 0.9998303651809692 0.01841968111693859 4.1081955714616925e-05 -1.1622647289044608e-16 -0.018419725820422173 0.9998288154602051 0.0017628732603043318 2.0 -8.603356945968699e-06 -0.0017633308889344335 0.9999984502792358 -2.001030634593559e-15 0.0 0.0 0.0 1.0 0.9955697059631348 0.09402430802583694 0.0005926893791183829 -5.967448757360216e-16 -0.09402582794427872 0.9955291152000427 0.008997068740427494 2.0 0.0002559037529863417 -0.009012939408421516 0.9999593496322632 9.993741945102386e-15 0.0 0.0 0.0 1.0 0.9817259907722473 0.19028612971305847 0.0022829289082437754 7.4505792646561986e-09 -0.19029591977596283 0.9815584421157837 0.018178554251790047 1.9999998807907104 0.0012182984501123428 -0.018280791118741035 0.9998321533203125 1.5727003033205733e-14 0.0 0.0 0.0 1.0 0.957146942615509 0.2895524203777313 0.005411616992205381 -1.915134717478395e-15 -0.28958943486213684 0.9567543268203735 0.027551069855690002 1.9999998807907104 0.00279989093542099 -0.027937568724155426 0.9996057748794556 6.661338147750939e-16 0.0 0.0 0.0 1.0 0.9201236367225647 0.3914887011051178 0.010444517247378826 -2.4424906541753444e-15 -0.3915977478027344 0.9193943738937378 0.03694813698530197 1.9999996423721313 0.004862145520746708 -0.0380869023501873 0.9992626309394836 -2.248201624865942e-14 0.0 0.0 0.0 1.0 0.8738107681274414 0.48596465587615967 0.017122987657785416 -2.7200464103316335e-15 -0.4862149953842163 0.8726656436920166 0.0452730767428875 2.0 0.007058470044285059 -0.04788554832339287 0.9988278746604919 5.928590951498336e-14 0.0 0.0 0.0 1.0 0.8255134224891663 0.5638235807418823 0.025112418457865715 2.9802318834981634e-08 -0.5643211603164673 0.8239501118659973 0.05145721137523651 2.000000238418579 0.008321406319737434 -0.05665009096264839 0.9983594417572021 2.6423307986078726e-14 0.0 0.0 0.0 1.0 0.7873582243919373 0.6155419945716858 0.03428023308515549 -2.980232594040899e-08 -0.616461992263794 0.7855148911476135 0.054230671375989914 1.999999761581421 0.0064536212012171745 -0.06383142620325089 0.9979398250579834 4.4853010194856324e-14 0.0 0.0 0.0 1.0 0.7748236656188965 0.6305439472198486 0.04541659727692604 -1.1920928955078125e-07 -0.6321731805801392 0.7730801701545715 0.05200223997235298 2.000000238418579 -0.0023209722712635994 -0.06900371611118317 0.9976137280464172 1.9539925233402755e-14 0.0 0.0 0.0 1.0 0.8074691891670227 0.5863681435585022 0.06454403698444366 6.511982064694166e-08 -0.5886243581771851 0.8080913424491882 0.022573528811335564 1.999999761581421 -0.03892108052968979 -0.05621962994337082 0.9976595044136047 -1.3969838619232178e-09 0.0 0.0 0.0 1.0 0.8808358907699585 0.4656791687011719 0.08527038991451263 1.8748687580227852e-07 -0.46402132511138916 0.8849409818649292 -0.039543673396110535 1.9999998807907104 -0.09387392550706863 -0.0047357818111777306 0.9955728650093079 -1.30385160446167e-08 0.0 0.0 0.0 1.0 0.9460473656654358 0.3024177849292755 0.11635156720876694 7.392372936010361e-08 -0.29019874334335327 0.950512170791626 -0.11095613986253738 1.9999995231628418 -0.14414867758750916 0.07120470702648163 0.9869908094406128 -1.862645149230957e-09 0.0 0.0 0.0 1.0 0.9779367446899414 0.14079925417900085 0.15432208776474 2.561137080192566e-07 -0.11382761597633362 0.9785844683647156 -0.17151015996932983 1.9999998807907104 -0.17516569793224335 0.15015996992588043 0.9730204939842224 -1.30385160446167e-08 0.0 0.0 0.0 1.0 0.9825076460838318 0.06423753499984741 0.17479248344898224 3.725290298461914e-08 -0.029007764533162117 0.9799563884735107 -0.19708888232707977 1.9999998807907104 -0.1839495152235031 0.1885710060596466 0.9646779298782349 2.2351741790771484e-08 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 2.2799733224976824e-14 -3.019916050561733e-07 -3.3881317890172014e-21 -2.2799733224976824e-14 1.0 0.0 2.0 3.019916050561733e-07 0.0 1.0 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 0.9998536109924316 0.01711064949631691 0.00039659717003814876 4.261721642251359e-09 -0.0171112772077322 0.9998522400856018 0.0016349750803783536 1.9999998807907104 -0.00036856307997368276 -0.001641521812416613 0.9999986290931702 4.5565684558823705e-10 0.0 0.0 0.0 1.0 0.99617999792099 0.08729173988103867 0.0023786951787769794 -2.3610937205376104e-08 -0.08730863034725189 0.9961469769477844 0.008274005725979805 2.000000238418579 -0.0016472784336656332 -0.00845007598400116 0.9999629259109497 7.712515071034431e-09 0.0 0.0 0.0 1.0 0.9842609167098999 0.17661483585834503 0.00612880103290081 4.011599230580032e-08 -0.17669369280338287 0.984127402305603 0.01651296205818653 2.000000238418579 -0.0031150872819125652 -0.017335979267954826 0.9998448491096497 -1.6298145055770874e-09 0.0 0.0 0.0 1.0 0.9631130695343018 0.2688666880130768 0.011120881885290146 1.9393337424844503e-07 -0.2690659761428833 0.9628040194511414 0.02473120391368866 1.9999990463256836 -0.0040578339248895645 -0.026811204850673676 0.9996322393417358 -1.7695128917694092e-08 0.0 0.0 0.0 1.0 0.931238055229187 0.36400336027145386 0.017243409529328346 2.486049197614193e-07 -0.36438867449760437 0.9306660890579224 0.032886967062950134 1.9999995231628418 -0.004076894372701645 -0.036908891052007675 0.999310314655304 -5.587935447692871e-09 0.0 0.0 0.0 1.0 0.8912754058837891 0.4528215229511261 0.02409932389855385 -3.2654497772455215e-07 -0.45345044136047363 0.8903771638870239 0.04014023765921593 1.999999761581421 -0.003281119279563427 -0.04670385271310806 0.9989033341407776 1.1175870895385742e-08 0.0 0.0 0.0 1.0 0.8494575619697571 0.5267446041107178 0.031019873917102814 4.7672074288129807e-07 -0.5276526808738708 0.8482257723808289 0.045782655477523804 2.000000238418579 -0.002196100540459156 -0.0552581250667572 0.9984697103500366 0.0 0.0 0.0 0.0 1.0 0.8163167238235474 0.5764156579971313 0.037040553987026215 -3.995373845100403e-07 -0.5776014924049377 0.8148404955863953 0.0491071380674839 2.000000238418579 -0.00187602115329355 -0.06148165464401245 0.9981064200401306 -1.4901161193847656e-08 0.0 0.0 0.0 1.0 0.8055055141448975 0.5911691188812256 0.040987249463796616 2.2811582311987877e-07 -0.592576265335083 0.8039996027946472 0.04937676340341568 2.000000238418579 -0.0037637173663824797 -0.06406132876873016 0.9979389309883118 -1.4901161193847656e-08 0.0 0.0 0.0 1.0 0.8542895317077637 0.5183570981025696 0.038668498396873474 -2.1746382117271423e-07 -0.5196048021316528 0.8536322116851807 0.03637533634901047 2.000000476837158 -0.014153261668980122 -0.05116738751530647 0.9985899329185486 -1.862645149230957e-09 0.0 0.0 0.0 1.0 0.9508073925971985 0.30806994438171387 0.03252604231238365 -3.5390257835388184e-08 -0.3083057403564453 0.9512842297554016 0.002376377582550049 1.9999996423721313 -0.030209438875317574 -0.012287446297705173 0.9994679689407349 2.9802322387695312e-08 0.0 0.0 0.0 1.0 0.9992246031761169 0.01764739491045475 0.03519628569483757 3.296881914138794e-07 -0.016185099259018898 0.999011218547821 -0.041407715529203415 1.999999761581421 -0.03589221462607384 0.04080595448613167 0.9985222220420837 1.4901161193847656e-08 0.0 0.0 0.0 1.0 0.9651545882225037 -0.25707417726516724 0.04888274520635605 1.1548399925231934e-07 0.26034310460090637 0.9621813893318176 -0.08017843961715698 2.000000476837158 -0.026422247290611267 0.09011086821556091 0.9955812096595764 1.4901161193847656e-08 0.0 0.0 0.0 1.0 0.9240012168884277 -0.37787526845932007 0.05858353525400162 3.725290298461914e-09 0.38199254870414734 0.919124186038971 -0.09639789164066315 2.000000476837158 -0.01741916500031948 0.11145025491714478 0.9936173558235168 1.4901161193847656e-08 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333334 0.125 0.16666666666666666 0.20833333333333334 0.24999999999999997 0.29166666666666663 0.3333333333333333 0.37499999999999994 0.41666666666666663 0.4583333333333333 0.49999999999999994 0.5416666666666666 0.5833333333333334 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 -1.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 -0.9340413808822632 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 1.7763568394002505e-15 0.0 1.0 7.549790126404332e-08 -0.6646065711975098 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 -7.105427357601002e-15 0.0 1.0 7.549790126404332e-08 -0.3219858407974243 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 -7.105427357601002e-15 0.0 1.0 7.549790126404332e-08 0.03573417663574219 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 -1.4210854715202004e-14 0.0 1.0 7.549790126404332e-08 0.41436636447906494 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 -1.4210854715202004e-14 0.0 1.0 7.549790126404332e-08 0.7831066846847534 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 -2.842170943040401e-14 0.0 1.0 7.549790126404332e-08 1.107043743133545 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 1.336852788925171 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 1.407799482345581 0.0 0.0 0.0 1.0 0.9968345761299133 0.07932797819375992 0.005282554775476456 0.0 0.004770305939018726 0.006645471788942814 -0.999966561794281 -1.4210854715202004e-14 -0.07936043292284012 0.9968264102935791 0.006246017292141914 1.193772792816162 0.0 0.0 0.0 1.0 0.9586331844329834 0.2838432192802429 0.021341901272535324 0.0 0.014647725969552994 0.02568591572344303 -0.9995627403259277 0.0 -0.2842673063278198 0.958526611328125 0.02046571485698223 0.6453161239624023 0.0 0.0 0.0 1.0 0.8506482243537903 0.5237787365913391 0.04531409963965416 0.0 0.02114533632993698 0.05203593522310257 -0.998421311378479 -7.105427357601002e-15 -0.5253098607063293 0.8502635359764099 0.033188797533512115 -0.037257254123687744 0.0 0.0 0.0 1.0 0.6941251158714294 0.7164199352264404 0.0702333077788353 0.0 0.020735301077365875 0.07762672752141953 -0.9967668652534485 3.552713678800501e-15 -0.7195556163787842 0.6933372616767883 0.03902747482061386 -0.6890351176261902 0.0 0.0 0.0 1.0 0.6061614155769348 0.7910918593406677 0.08210963010787964 0.0 0.018376974388957024 0.08927963674068451 -0.9958370327949524 0.0 -0.7951292991638184 0.6051469445228577 0.039580002427101135 -1.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 3.019916050561733e-07 -1.6940658945086007e-21 -3.3881317890172014e-21 -2.8421682325349695e-14 7.549790126404332e-08 1.0 2.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 2.740863092043355e-16 4.542739340078483e-15 -2.787898662197797e-14 7.549790126404332e-08 1.0 1.999999761581421 2.980232238769531e-07 -1.0 7.549790126404332e-08 -6.111760132276184e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -4.440892098500626e-16 -3.693798874626966e-15 -2.509833839240208e-14 7.549790836947068e-08 1.0 2.0 2.980232238769531e-07 -1.0 7.549790836947068e-08 1.9710300828545274e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 0.0 -2.5217366850282044e-14 -2.7558835272970157e-14 7.549790126404332e-08 1.0 1.999999761581421 2.980232238769531e-07 -1.0 7.549790126404332e-08 1.2755667358412166e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -1.7763568394002505e-15 -5.464224111704184e-14 -2.4811610963492922e-14 7.549790126404332e-08 1.0 2.0 2.980232238769531e-07 -1.0 7.549790126404332e-08 -8.798196444667356e-15 0.0 0.0 0.0 1.0 1.0 3.0199157663446385e-07 -7.111923615526905e-22 -2.0328790734103208e-20 -2.84216806312838e-14 7.549789415861596e-08 1.0 1.999999761581421 3.019916050561733e-07 -1.0 7.549789415861596e-08 -1.4210912313442417e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -4.440892098500626e-16 1.5987211554602254e-14 -3.019806626980426e-14 7.549790126404332e-08 1.0 1.999999761581421 2.980232238769531e-07 -1.0 7.549790836947068e-08 -3.552713678800501e-15 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -8.881784197001252e-16 -4.440892098500626e-15 -2.842170943040401e-14 7.549789415861596e-08 1.0 2.000000238418579 2.980232238769531e-07 -0.9999999403953552 7.549789415861596e-08 2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0000001192092896 2.980232238769531e-07 -1.7763568394002505e-15 1.3322676295501878e-14 -2.842170943040401e-14 7.549790836947068e-08 1.0 1.999999761581421 2.980232238769531e-07 -1.0000001192092896 7.549790126404332e-08 -1.0658141036401503e-14 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -4.440892098500626e-16 1.3322676295501878e-15 -2.7977620220553945e-14 7.549790126404332e-08 1.0 2.000000238418579 2.980232238769531e-07 -1.0 7.549789415861596e-08 -2.3092638912203256e-14 0.0 0.0 0.0 1.0 1.0 3.019916050561733e-07 -7.9063885886186065e-22 -1.0164395367051604e-20 -2.8421682325349695e-14 7.549790126404332e-08 1.0 2.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 2.842169587787685e-14 0.0 0.0 0.0 1.0 1.0 3.2782554626464844e-07 1.3322676295501878e-15 5.6066262743570405e-15 -2.693678613496786e-14 7.549790836947068e-08 1.0 2.0 3.2782554626464844e-07 -1.0 7.549789415861596e-08 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 2.980232238769531e-07 -1.6653345369377348e-15 9.325873406851315e-15 -2.3314683517128287e-14 7.549790836947068e-08 1.0 2.000000238418579 2.980232238769531e-07 -1.0000001192092896 7.549789415861596e-08 -7.105427357601002e-14 0.0 0.0 0.0 1.0 1.0 2.682209014892578e-07 1.3322676295501878e-15 -5.329070518200751e-15 -3.019806626980426e-14 7.549791547489804e-08 1.0 1.999999761581421 2.682209014892578e-07 -1.0000001192092896 7.549790126404332e-08 -3.552713678800501e-14 0.0 0.0 0.0 1.0 0.9999999403953552 2.980232238769531e-07 -3.1086244689504383e-15 3.552713678800501e-15 -2.842170943040401e-14 7.549789415861596e-08 1.0 2.0 2.980232238769531e-07 -0.9999999403953552 7.549789415861596e-08 -4.263256414560601e-14 0.0 0.0 0.0 1.0 1.0 3.0199157663446385e-07 -2.117582368135751e-21 -1.6940658945086007e-21 -2.84216806312838e-14 7.549789415861596e-08 1.0 1.999999761581421 3.0199157663446385e-07 -1.0 7.549789415861596e-08 -2.842170265414043e-14 0.0 0.0 0.0 1.0 0.9999999403953552 2.980232238769531e-07 -1.7763568394002505e-15 -1.4210854715202004e-14 -3.108624468950438e-14 7.549789415861596e-08 1.0 2.000000238418579 2.980232238769531e-07 -0.9999999403953552 7.549789415861596e-08 1.2434497875801753e-14 0.0 0.0 0.0 1.0 1.0000001192092896 2.980232238769531e-07 2.6645352591003757e-15 2.1316282072803006e-14 -3.197442310920451e-14 7.549790836947068e-08 1.0 2.0 2.980232238769531e-07 -1.0000001192092896 7.549790126404332e-08 -7.105427357601002e-14 0.0 0.0 0.0 1.0 0.9999999403953552 2.980232238769531e-07 4.884981308350689e-15 0.0 -2.4868995751603507e-14 7.549790126404332e-08 1.0 2.000000238418579 2.980232238769531e-07 -0.9999999403953552 7.549790126404332e-08 0.0 0.0 0.0 0.0 1.0 1.0 2.905726432800293e-07 -2.831068712794149e-15 7.105427357601002e-14 -2.9753977059954195e-14 7.549790836947068e-08 1.0 1.999999761581421 2.905726432800293e-07 -1.0 7.549790126404332e-08 2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0 3.019916050561733e-07 -4.5171351782337e-22 8.470329472543003e-21 -2.8421682325349695e-14 7.549790126404332e-08 1.0 2.0 3.019916050561733e-07 -1.0 7.549790126404332e-08 -4.658681209898652e-21 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 1.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 -5.342710077992151e-16 0.0 8.862057858450884e-16 1.0 -7.0636156937421615e-15 2.0 -5.342710607387743e-16 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0000001192092896 0.0 -1.9771030126248092e-15 0.0 3.552713678800501e-15 1.0 -7.105427357601002e-15 2.0 -1.9771030126248092e-15 0.0 1.0000001192092896 0.0 0.0 0.0 0.0 1.0 1.0 0.0 -2.8464326199079213e-15 0.0 0.0 1.0 0.0 2.0 -2.8464326199079213e-15 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 -1.7659080527211582e-15 0.0 -5.825547445289072e-16 1.0 9.824089292580348e-17 2.0 -1.7659079468420398e-15 -1.7763568394002505e-15 1.0 -3.552713678800501e-15 0.0 0.0 0.0 1.0 1.0 8.470329472543003e-22 3.070531895223506e-22 1.6940658945086007e-21 0.0 1.0 7.105425240018634e-15 2.0 5.364448530829927e-22 -7.105429051666896e-15 1.0 -1.4210858103333793e-14 0.0 0.0 0.0 1.0 0.9999999403953552 -8.881784197001252e-16 -5.579573312571159e-16 -1.7763568394002505e-15 -8.881784197001252e-16 1.0 3.1086244689504383e-15 2.0 -5.579571194988791e-16 -3.774758283725532e-15 0.9999999403953552 -7.549516567451064e-15 0.0 0.0 0.0 1.0 0.9999999403953552 8.881784197001252e-16 -6.462154115039354e-16 1.7763568394002505e-15 1.7763568394002505e-15 1.0 1.7763568394002505e-15 2.0 -6.462157291412906e-16 8.881784197001252e-16 0.9999999403953552 1.7763568394002505e-15 0.0 0.0 0.0 1.0 1.0 8.881784197001252e-16 2.9802322387695312e-08 1.7763568394002505e-15 1.7763568394002505e-15 1.0 -3.552713678800501e-15 2.0 -2.9802322387695312e-08 -5.329070518200751e-15 1.0 -1.0658141036401503e-14 0.0 0.0 0.0 1.0 1.0 -8.881784197001252e-16 -2.101767204219329e-16 -1.7763568394002505e-15 0.0 1.0 4.440892098500626e-16 2.0 -2.101765748381451e-16 -4.440892098500626e-16 1.0 -8.881784197001252e-16 0.0 0.0 0.0 1.0 1.0 0.0 -3.81167065240496e-36 0.0 0.0 1.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 2.7755575615628914e-17 -1.699426852058557e-17 5.551115123125783e-17 0.0 1.0 -6.661338147750939e-15 2.0 -1.699427182930802e-17 7.549516567451064e-15 1.0 1.509903313490213e-14 0.0 0.0 0.0 1.0 1.0 3.9968028886505635e-15 -2.9802322387695312e-08 7.993605777301127e-15 3.552713678800501e-15 1.0 -7.105427357601002e-15 2.0 2.9802322387695312e-08 -5.329070518200751e-15 1.0 -1.0658141036401503e-14 0.0 0.0 0.0 1.0 1.0 -1.7763568394002505e-15 -6.745567104025907e-16 -3.552713678800501e-15 0.0 1.0 -7.105427357601002e-15 2.0 -6.745576103750971e-16 -3.552713678800501e-15 1.0000001192092896 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -1.7763568394002505e-15 -1.7359223452345271e-15 -3.552713678800501e-15 -1.7763568394002505e-15 1.0 -1.7763568394002505e-15 2.0 -1.7359214982015799e-15 -2.6645352591003757e-15 1.0 -5.329070518200751e-15 0.0 0.0 0.0 1.0 1.0 -8.470329472543003e-22 -3.0705321476589955e-22 -1.6940658945086007e-21 8.470329472543003e-22 1.0 7.105425240018634e-15 2.0 -5.364448025958947e-22 -7.105429051666896e-15 1.0 -1.4210858103333793e-14 0.0 0.0 0.0 1.0 0.9999999403953552 -1.7763568394002505e-15 -1.4652425907858116e-15 -3.552713678800501e-15 8.881784197001252e-16 1.0 1.7763568394002505e-15 2.0 -1.4652424849066932e-15 2.220446049250313e-15 0.9999999403953552 4.440892098500626e-15 0.0 0.0 0.0 1.0 1.0 1.7763568394002505e-15 -4.434845130290178e-15 3.552713678800501e-15 1.7763568394002505e-15 1.0 1.7763568394002505e-15 2.0 -4.434845553806651e-15 -7.105427357601002e-15 1.0 -1.4210854715202004e-14 0.0 0.0 0.0 1.0 1.0 0.0 2.9802315282267955e-08 0.0 -1.7763568394002505e-15 1.0 0.0 2.0 -2.980232949312267e-08 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 -8.881784197001252e-16 -8.063171746226176e-15 -1.7763568394002505e-15 -1.3322676295501878e-15 1.0 -6.217248937900877e-15 2.0 -8.063172593259123e-15 7.105427357601002e-15 1.0 1.4210854715202004e-14 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 2.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 -2.2799733224976824e-14 3.019916050561733e-07 0.0 2.2799733224976824e-14 1.0 0.0 2.0 -3.019916050561733e-07 0.0 1.0 7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -2.259762777563016e-14 2.980232238769531e-07 -4.440892098500626e-16 2.353475622935211e-14 1.0 -7.0636156937421615e-15 2.0 -2.980232238769531e-07 -2.137084242955097e-15 1.0 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -2.1386826364782133e-14 2.980232238769531e-07 -3.552713678800501e-15 2.4868995751603507e-14 1.0 -7.105427357601002e-15 2.0 -2.980232238769531e-07 -8.02984692898235e-16 1.0 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -2.149046931620817e-14 2.980232238769531e-07 -7.105427357601002e-15 2.1316282072803006e-14 1.0 0.0 2.0 -2.980232238769531e-07 -7.275902902631297e-16 1.0 -3.552713678800501e-15 0.0 0.0 0.0 1.0 1.0 -2.3768408573786315e-14 3.2782554626464844e-07 7.105427357601002e-15 2.0733728387065282e-14 1.0 1.8745974146886987e-15 2.0 -3.2782554626464844e-07 -1.7345621162003552e-15 1.0 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -2.279973153091093e-14 3.019916050561733e-07 3.3881317890172014e-21 2.2799733224976824e-14 1.0 7.1054197343044766e-15 2.0 -3.0199157663446385e-07 -7.105432439798685e-15 1.0 -2.1316288849066584e-14 0.0 0.0 0.0 1.0 1.0 -2.398081733190338e-14 2.980232238769531e-07 -2.6645352591003757e-15 2.220446049250313e-14 1.0 0.0 2.0 -2.980232238769531e-07 -3.1086244689504383e-15 1.0 -1.509903313490213e-14 0.0 0.0 0.0 1.0 1.0 -2.398081733190338e-14 2.980232238769531e-07 2.6645352591003757e-15 2.220446049250313e-14 1.0 4.440892098500626e-15 2.0 -2.980232238769531e-07 1.7763568394002505e-15 1.0 0.0 0.0 0.0 0.0 1.0 1.0000001192092896 -2.042810365310288e-14 2.980232238769531e-07 2.6645352591003757e-15 2.3092638912203256e-14 1.0 -3.552713678800501e-15 2.0 -2.980232238769531e-07 -3.552713678800501e-15 1.0000001192092896 -1.7763568394002505e-14 0.0 0.0 0.0 1.0 0.9999999403953552 -2.220446049250313e-14 2.980232238769531e-07 -3.552713678800501e-15 2.1316282072803006e-14 1.0 0.0 2.0 -2.980232238769531e-07 8.881784197001252e-16 0.9999999403953552 -5.329070518200751e-15 0.0 0.0 0.0 1.0 1.0 -2.2799733224976824e-14 3.019916050561733e-07 0.0 2.2799733224976824e-14 1.0 0.0 2.0 -3.019916050561733e-07 0.0 1.0 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0000001192092896 -2.1288526497187377e-14 2.980232238769531e-07 1.3877787807814457e-16 2.4424906541753444e-14 1.0 -6.217248937900877e-15 2.0 -2.980232238769531e-07 8.43769498715119e-15 1.0000001192092896 3.730349362740526e-14 0.0 0.0 0.0 1.0 1.0 -1.7319479184152442e-14 2.980232238769531e-07 1.5987211554602254e-14 2.3092638912203256e-14 1.0 -3.552713678800501e-15 2.0 -2.980232238769531e-07 -1.7763568394002505e-15 1.0000001192092896 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 -2.3092638912203256e-14 3.2782554626464844e-07 -7.105427357601002e-15 2.042810365310288e-14 1.0 -3.552713678800501e-15 2.0 -3.2782554626464844e-07 -3.552713678800501e-15 1.0000001192092896 -2.1316282072803006e-14 0.0 0.0 0.0 1.0 0.9999999403953552 -2.1316282072803006e-14 2.980232238769531e-07 -7.105427357601002e-15 1.7763568394002505e-14 1.0 -1.7763568394002505e-15 2.0 -2.980232238769531e-07 -3.552713678800501e-15 0.9999999403953552 -3.552713678800501e-15 0.0 0.0 0.0 1.0 1.0 -2.279973491904272e-14 3.019916050561733e-07 -3.3881317890172014e-21 2.279973153091093e-14 1.0 7.105429898699844e-15 2.0 -3.019916050561733e-07 -7.105426087051581e-15 1.0 -2.8421716206667585e-14 0.0 0.0 0.0 1.0 0.9999999403953552 -2.5757174171303632e-14 3.2782554626464844e-07 -7.105427357601002e-15 2.398081733190338e-14 1.0 -1.7763568394002505e-15 2.0 -3.2782554626464844e-07 2.220446049250313e-15 0.9999999403953552 1.5987211554602254e-14 0.0 0.0 0.0 1.0 1.0000001192092896 -1.7763568394002505e-14 2.980232238769531e-07 1.0658141036401503e-14 2.1316282072803006e-14 1.0 1.7763568394002505e-15 2.0 -2.980232238769531e-07 -5.329070518200751e-15 1.0000001192092896 -2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0 -1.7763568394002505e-14 2.980232238769531e-07 7.105427357601002e-15 1.9539925233402755e-14 1.0 0.0 2.0 -2.980232238769531e-07 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 -2.220446049250313e-14 2.980232238769531e-07 -3.552713678800501e-15 1.9984014443252818e-14 1.0 -2.6645352591003757e-15 2.0 -2.980232238769531e-07 8.881784197001252e-15 1.0 2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0 -2.2799733224976824e-14 3.019916050561733e-07 -4.235164736271502e-22 2.2799733224976824e-14 1.0 1.522012327097571e-21 2.0 -3.019916050561733e-07 0.0 1.0 0.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 2.2799733224976824e-14 -3.019916050561733e-07 -3.3881317890172014e-21 -2.2799733224976824e-14 1.0 0.0 2.0 3.019916050561733e-07 0.0 1.0 -2.8421722982931164e-14 0.0 0.0 0.0 1.0 1.0 2.2648549702353193e-14 -2.980232238769531e-07 4.542739340078483e-15 -2.2105826893927157e-14 1.0 -2.0905738755796002e-15 1.999999761581421 2.980232238769531e-07 0.0 1.0 -6.111760132276184e-14 0.0 0.0 0.0 1.0 1.0 2.309263721813736e-14 -2.980232238769531e-07 -3.693798874626966e-15 -1.976926787420133e-14 1.0 -7.972451129443451e-15 2.0 2.980232238769531e-07 -6.352747104407253e-22 1.0 1.9710300828545274e-14 0.0 0.0 0.0 1.0 1.0 2.1316276990605322e-14 -2.980232238769531e-07 -2.5217366850282044e-14 -2.0453407915369155e-14 1.0 3.6245386845958766e-16 1.999999761581421 2.980232238769531e-07 -4.910144116114772e-21 1.0 1.2755667358412166e-14 0.0 0.0 0.0 1.0 1.0 1.4210852174103162e-14 -2.980232238769531e-07 -5.464224111704184e-14 -1.770618360589192e-14 1.0 -2.963268533003917e-15 2.0 2.980232238769531e-07 -1.776363192147355e-15 1.0 -8.798196444667356e-15 0.0 0.0 0.0 1.0 1.0 2.279973491904272e-14 -3.0199157663446385e-07 -2.0328790734103208e-20 -2.279973153091093e-14 1.0 7.105421851886845e-15 1.999999761581421 3.019916050561733e-07 -7.105433286831633e-15 1.0 -1.4210912313442417e-14 0.0 0.0 0.0 1.0 1.0 2.4868995751603507e-14 -2.980232238769531e-07 1.5987211554602254e-14 -2.4868995751603507e-14 1.0 3.3306690738754696e-15 1.999999761581421 2.980232238769531e-07 4.440892098500626e-16 1.0 -3.552713678800501e-15 0.0 0.0 0.0 1.0 1.0 2.220446049250313e-14 -2.980232238769531e-07 -4.440892098500626e-15 -2.3092638912203256e-14 1.0 8.881784197001252e-16 2.000000238418579 2.980232238769531e-07 -3.552713678800501e-15 1.0 2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0000001192092896 2.220446049250313e-14 -2.980232238769531e-07 1.3322676295501878e-14 -2.3092638912203256e-14 1.0 0.0 1.999999761581421 2.980232238769531e-07 -1.7763568394002505e-15 1.0000001192092896 -1.0658141036401503e-14 0.0 0.0 0.0 1.0 1.0 2.0872192862952943e-14 -2.980232238769531e-07 1.3322676295501878e-15 -2.220446049250313e-14 1.0 3.552713678800501e-15 2.000000238418579 2.980232238769531e-07 -3.1086244689504383e-15 1.0 -2.3092638912203256e-14 0.0 0.0 0.0 1.0 1.0 2.2799733224976824e-14 -3.019916050561733e-07 -1.0164395367051604e-20 -2.2799733224976824e-14 1.0 0.0 2.0 3.019916050561733e-07 0.0 1.0 2.842169587787685e-14 0.0 0.0 0.0 1.0 1.0 2.3148150063434514e-14 -3.2782554626464844e-07 5.6066262743570405e-15 -2.1316282072803006e-14 1.0 -5.329070518200751e-15 2.0 3.2782554626464844e-07 -5.329070518200751e-15 1.0 -7.105427357601002e-15 0.0 0.0 0.0 1.0 1.0 2.1760371282653068e-14 -2.980232238769531e-07 9.325873406851315e-15 -1.7763568394002505e-14 1.0 -7.105427357601002e-15 2.000000238418579 2.980232238769531e-07 -8.881784197001252e-15 1.0000001192092896 -7.105427357601002e-14 0.0 0.0 0.0 1.0 1.0 2.3092638912203256e-14 -2.682209014892578e-07 -5.329070518200751e-15 -2.4868995751603507e-14 1.0 -1.4210854715202004e-14 1.999999761581421 2.682209014892578e-07 0.0 1.0000001192092896 -3.552713678800501e-14 0.0 0.0 0.0 1.0 0.9999999403953552 2.1316282072803006e-14 -2.980232238769531e-07 3.552713678800501e-15 -2.3092638912203256e-14 1.0 4.440892098500626e-15 2.0 2.980232238769531e-07 -4.440892098500626e-15 0.9999999403953552 -4.263256414560601e-14 0.0 0.0 0.0 1.0 1.0 2.2799733224976824e-14 -3.019916050561733e-07 -1.6940658945086007e-21 -2.2799733224976824e-14 1.0 7.105428204633949e-15 1.999999761581421 3.0199157663446385e-07 -7.10542481650216e-15 1.0 -2.842170265414043e-14 0.0 0.0 0.0 1.0 0.9999999403953552 1.9539925233402755e-14 -2.980232238769531e-07 -1.4210854715202004e-14 -2.5757174171303632e-14 1.0 9.325873406851315e-15 2.000000238418579 2.980232238769531e-07 -1.7763568394002505e-15 0.9999999403953552 1.2434497875801753e-14 0.0 0.0 0.0 1.0 1.0000001192092896 2.842170943040401e-14 -2.980232238769531e-07 2.1316282072803006e-14 -2.4868995751603507e-14 1.0 -3.552713678800501e-15 2.0 2.980232238769531e-07 -1.7763568394002505e-15 1.0000001192092896 -7.105427357601002e-14 0.0 0.0 0.0 1.0 0.9999999403953552 2.3092638912203256e-14 -2.980232238769531e-07 0.0 -1.7763568394002505e-14 1.0 0.0 2.000000238418579 2.980232238769531e-07 0.0 0.9999999403953552 0.0 0.0 0.0 0.0 1.0 1.0 1.9984014443252818e-14 -2.905726432800293e-07 7.105427357601002e-14 -2.2648549702353193e-14 1.0 -4.440892098500626e-15 1.999999761581421 2.905726432800293e-07 3.552713678800501e-15 1.0 2.1316282072803006e-14 0.0 0.0 0.0 1.0 1.0 2.2799733224976824e-14 -3.019916050561733e-07 8.470329472543003e-21 -2.2799733224976824e-14 1.0 0.0 2.0 3.019916050561733e-07 1.522012327097571e-21 1.0 -4.658681209898652e-21 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + 0.0 0.041666666666666664 0.08333333333333333 0.125 0.16666666666666666 0.20833333333333331 0.25 0.29166666666666663 0.3333333333333333 0.375 0.41666666666666663 0.4583333333333333 0.5 0.5416666666666666 0.5833333333333333 0.625 0.6666666666666666 0.7083333333333333 0.75 0.7916666666666666 0.8333333333333333 + + + + + + + + 1.0 0.0 0.0 0.0 0.0 7.549790126404332e-08 -1.0 0.0 0.0 1.0 7.549790126404332e-08 -1.0 0.0 0.0 0.0 1.0 0.9955579042434692 0.0 0.0941510796546936 0.0 0.0941510796546936 7.549790126404332e-08 -0.9955579042434692 0.0 -7.108209132411503e-09 1.0 7.516253219819191e-08 -1.0 0.0 0.0 0.0 1.0 0.9274256825447083 0.0 0.37400758266448975 0.0 0.37400758266448975 7.549790126404332e-08 -0.9274256825447083 0.0 -2.8236787130708763e-08 1.0 7.001869306577646e-08 -1.0 0.0 0.0 0.0 1.0 0.6892805695533752 0.0 0.7244945168495178 0.0 0.7244945168495178 7.549790126404332e-08 -0.6892805695533752 0.0 -5.469781427791531e-08 1.0 5.2039236919654286e-08 -1.0 0.0 0.0 0.0 1.0 0.327949196100235 0.0 0.9446954131126404 0.0 0.9446954131126404 7.549790126404332e-08 -0.327949196100235 0.0 -7.132251766961417e-08 1.0 2.4759476247027123e-08 -1.0 0.0 0.0 0.0 1.0 -1.3435885648505064e-07 -7.549791547489804e-08 1.0000001192092896 0.0 1.0000001192092896 -1.4210854715202004e-14 1.3435885648505064e-07 0.0 7.105427357601002e-15 1.0 7.549790836947068e-08 -1.0 0.0 0.0 0.0 1.0 -0.2926259934902191 -6.342676073245457e-08 0.9562267661094666 0.0 0.9562267661094666 -1.0242303005725262e-08 0.2926259934902191 0.0 -8.766356529577024e-09 1.0 6.364755478216466e-08 -1.0 0.0 0.0 0.0 1.0 -0.580210268497467 -4.877818682302859e-08 0.8144668340682983 0.0 0.8144668340682983 -1.914044389650371e-08 0.580210268497467 0.0 -1.2712352059907062e-08 1.0 5.0833687481599554e-08 -1.0 0.0 0.0 0.0 1.0 -0.8144670128822327 -3.242801938085904e-08 0.5802100896835327 0.0 0.5802100896835327 -2.5912903822700173e-08 0.8144670128822327 0.0 -1.1376624087233722e-08 1.0 3.9920251992953126e-08 -1.0 0.0 0.0 0.0 1.0 -0.9562267661094666 -1.5777985140630335e-08 0.29262611269950867 0.0 0.29262611269950867 -2.997906989321564e-08 0.9562267661094666 0.0 -6.314671452400944e-09 1.0 3.3283853895227367e-08 -1.0 0.0 0.0 0.0 1.0 -1.0 4.303330901289246e-22 -5.699934153277153e-15 0.0 -5.699934153277153e-15 -7.549791547489804e-08 1.0 0.0 0.0 1.0 7.549791547489804e-08 -1.0 0.0 0.0 0.0 1.0 -0.9562270045280457 2.2313441760957176e-08 -0.29262617230415344 0.0 -0.29262617230415344 -7.366906373817983e-08 0.9562270045280457 0.0 -2.2077983885537833e-10 1.0 7.697383352933684e-08 -1.0 0.0 0.0 0.0 1.0 -0.8144670128822327 4.5860144126663727e-08 -0.5802100896835327 0.0 -0.5802100896835327 -6.791864137767334e-08 0.8144670128822327 0.0 -2.0555006585709634e-09 1.0 8.192598954792629e-08 -1.0 0.0 0.0 0.0 1.0 -0.580210268497467 6.89827786004571e-08 -0.8144668936729431 0.0 -0.8144668936729431 -5.8340923203559214e-08 0.580210268497467 0.0 -7.492239717521443e-09 1.0 9.003416323594138e-08 -1.0 0.0 0.0 0.0 1.0 -0.29262620210647583 8.969897891120127e-08 -0.9562268257141113 0.0 -0.9562268257141113 -4.575706924470069e-08 0.29262620210647583 0.0 -1.7505861649169674e-08 1.0 9.916230681028537e-08 -1.0 0.0 0.0 0.0 1.0 -1.3435885648505064e-07 7.549790836947068e-08 -1.0000001192092896 0.0 -1.0000001192092896 -1.4210854715202004e-14 1.3435885648505064e-07 0.0 -7.105427357601002e-15 1.0 7.549790126404332e-08 -1.0 0.0 0.0 0.0 1.0 0.327949196100235 8.808321183551016e-08 -0.9446954727172852 0.0 -0.9446954727172852 1.283601136492507e-08 -0.327949196100235 0.0 -1.6760694165895984e-08 1.0 8.742135548800434e-08 -1.0 0.0 0.0 0.0 1.0 0.68928062915802 1.0117053506064622e-07 -0.7244945168495178 0.0 -0.7244945168495178 3.2108129488506165e-08 -0.68928062915802 0.0 -4.647272788815826e-08 1.0 9.542900158976408e-08 -1.0 0.0 0.0 0.0 1.0 0.9274256229400635 1.0772405545367292e-07 -0.37400758266448975 0.0 -0.37400758266448975 5.4594561760268334e-08 -0.9274256229400635 0.0 -7.948726477025048e-08 1.0 9.092201480598305e-08 -1.0 0.0 0.0 0.0 1.0 0.9955579042434692 1.0759762147927177e-07 -0.0941511020064354 0.0 -0.0941511020064354 7.042140026669585e-08 -0.9955579042434692 0.0 -1.0048940879414658e-07 1.0 8.023901898468466e-08 -1.0 0.0 0.0 0.0 1.0 1.0 5.024294934767972e-15 3.7932372841020008e-22 0.0 5.048709793414476e-29 7.549789415861596e-08 -1.0 0.0 -5.024294934767972e-15 1.0 7.549789415861596e-08 -1.0 0.0 0.0 0.0 1.0 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + + + diff --git a/test/models/OBJ/box_without_lineending.obj b/test/models/OBJ/box_without_lineending.obj new file mode 100644 index 000000000..80a201495 --- /dev/null +++ b/test/models/OBJ/box_without_lineending.obj @@ -0,0 +1,28 @@ +# Vertices: 8 +# Points: 0 +# Lines: 0 +# Faces: 6 +# Materials: 1 + +o 1 + +# Vertex list + +v -0.5 -0.5 0.5 +v -0.5 -0.5 -0.5 +v -0.5 0.5 -0.5 +v -0.5 0.5 0.5 +v 0.5 -0.5 0.5 +v 0.5 -0.5 -0.5 +v 0.5 0.5 -0.5 +v 0.5 0.5 0.5 + +# Point/Line/Face list + +usemtl Default +f 4 3 2 1 +f 2 6 5 1 +f 3 7 6 2 +f 8 7 3 4 +f 5 8 4 1 +f 6 7 8 5 \ No newline at end of file diff --git a/test/models/OBJ/cube_usemtl.mtl b/test/models/OBJ/cube_usemtl.mtl new file mode 100644 index 000000000..040e0adad --- /dev/null +++ b/test/models/OBJ/cube_usemtl.mtl @@ -0,0 +1,11 @@ +newmtl mtl +Ka 1.000 1.000 1.000 +Kd 1.000 1.000 1.000 +Ns 200.000 +Ks 0.050 0.050 0.050 + +newmtl mtl2 +Ka 1.000 1.000 1.000 +Kd 1.000 1.000 1.000 +Ns 16.000 +Ks 0.375 0.375 0.375 diff --git a/test/models/OBJ/cube_usemtl.obj b/test/models/OBJ/cube_usemtl.obj new file mode 100644 index 000000000..d840a28fc --- /dev/null +++ b/test/models/OBJ/cube_usemtl.obj @@ -0,0 +1,44 @@ +mtllib cube_usemtl.mtl + +g cube + +v 0.0 0.0 0.0 +v 0.0 0.0 1.0 +v 0.0 1.0 0.0 +v 0.0 1.0 1.0 +v 1.0 0.0 0.0 +v 1.0 0.0 1.0 +v 1.0 1.0 0.0 +v 1.0 1.0 1.0 + +vn 0.0 0.0 1.0 +vn 0.0 0.0 -1.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 +vn 1.0 0.0 0.0 +vn -1.0 0.0 0.0 + +usemtl mtl3 +f 1//2 7//2 5//2 +usemtl mtl3 +f 1//2 3//2 7//2 +usemtl mtl +f 1//6 4//6 3//6 +usemtl mtl +f 1//6 2//6 4//6 +usemtl mtl +f 3//3 8//3 7//3 +usemtl mtl2 +f 3//3 4//3 8//3 +usemtl mtl2 +f 5//5 7//5 8//5 +usemtl mtl2 +f 5//5 8//5 6//5 +usemtl mtl2 +f 1//4 5//4 6//4 +usemtl mtl +f 1//4 6//4 2//4 +usemtl mtl +f 2//1 6//1 8//1 +usemtl mtl +f 2//1 8//1 4//1 diff --git a/test/models/OFF/invalid.off b/test/models/OFF/invalid.off new file mode 100644 index 000000000..7ceb8bf85 --- /dev/null +++ b/test/models/OFF/invalid.off @@ -0,0 +1,8 @@ +OFF +3 4 +0.1 0.2 0.3 +0.2 0.3 0.4 +0.3 0.4 0.5 +0 +2 20 +4 diff --git a/test/models/SIB/This Way Up.png b/test/models/SIB/This Way Up.png new file mode 100644 index 000000000..87c8ba1dc Binary files /dev/null and b/test/models/SIB/This Way Up.png differ diff --git a/test/models/SIB/UV Mapping.png b/test/models/SIB/UV Mapping.png new file mode 100644 index 000000000..3d8e235d4 Binary files /dev/null and b/test/models/SIB/UV Mapping.png differ diff --git a/test/models/SIB/heffalump.sib b/test/models/SIB/heffalump.sib new file mode 100644 index 000000000..00d6bfb51 Binary files /dev/null and b/test/models/SIB/heffalump.sib differ diff --git a/test/models/SIB/readme.txt b/test/models/SIB/readme.txt new file mode 100644 index 000000000..4a83c0ea4 --- /dev/null +++ b/test/models/SIB/readme.txt @@ -0,0 +1,3 @@ +Made by me (Richard Mitton). +I waive all rights to this and release it into the public domain. +Do with it as you wish. diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.bin b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.bin new file mode 100644 index 000000000..e718eec4d Binary files /dev/null and b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.bin differ diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.gltf b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.gltf new file mode 100644 index 000000000..0d66c6fe3 --- /dev/null +++ b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.gltf @@ -0,0 +1,705 @@ +{ + "accessors": { + "accessor_100": { + "bufferView": "bufferView_105", + "byteOffset": 7032, + "byteStride": 12, + "componentType": 5126, + "count": 586, + "max": [ + 0.999039, + 0.999038, + 1 + ], + "min": [ + -0.999038, + -0.999038, + -1 + ], + "type": "VEC3" + }, + "accessor_102": { + "bufferView": "bufferView_105", + "byteOffset": 14064, + "byteStride": 8, + "componentType": 5126, + "count": 586, + "max": [ + 0.993657, + 0.989576 + ], + "min": [ + 0.605093, + 0.00905001 + ], + "type": "VEC2" + }, + "accessor_63": { + "bufferView": "bufferView_104", + "byteOffset": 4608, + "byteStride": 0, + "componentType": 5123, + "count": 5232, + "type": "SCALAR" + }, + "accessor_66": { + "bufferView": "bufferView_104", + "byteOffset": 15072, + "byteStride": 0, + "componentType": 5123, + "count": 168, + "type": "SCALAR" + }, + "accessor_69": { + "bufferView": "bufferView_104", + "byteOffset": 15408, + "byteStride": 0, + "componentType": 5123, + "count": 864, + "type": "SCALAR" + }, + "accessor_71": { + "bufferView": "bufferView_105", + "byteOffset": 18752, + "byteStride": 12, + "componentType": 5126, + "count": 2392, + "max": [ + 2.438, + 2.58437, + 1.396 + ], + "min": [ + -2.43091, + 0.2668, + -1.396 + ], + "type": "VEC3" + }, + "accessor_73": { + "bufferView": "bufferView_105", + "byteOffset": 47456, + "byteStride": 12, + "componentType": 5126, + "count": 2392, + "max": [ + 1, + 1, + 1 + ], + "min": [ + -1, + -1, + -1 + ], + "type": "VEC3" + }, + "accessor_75": { + "bufferView": "bufferView_105", + "byteOffset": 76160, + "byteStride": 8, + "componentType": 5126, + "count": 2392, + "max": [ + 0.896458, + 0.997245 + ], + "min": [ + 0.00295639, + 0.015672 + ], + "type": "VEC2" + }, + "accessor_96": { + "bufferView": "bufferView_104", + "byteOffset": 0, + "byteStride": 0, + "componentType": 5123, + "count": 2304, + "type": "SCALAR" + }, + "accessor_98": { + "bufferView": "bufferView_105", + "byteOffset": 0, + "byteStride": 12, + "componentType": 5126, + "count": 586, + "max": [ + 0.4278, + 0.4278, + 1.058 + ], + "min": [ + -0.4278, + -0.4278, + -1.058 + ], + "type": "VEC3" + }, + "animAccessor_0": { + "bufferView": "bufferView_103", + "byteOffset": 0, + "componentType": 5126, + "count": 31, + "type": "SCALAR" + }, + "animAccessor_1": { + "bufferView": "bufferView_103", + "byteOffset": 124, + "componentType": 5126, + "count": 31, + "type": "VEC4" + } + }, + "animations": { + "animation_0": { + "channels": [ + { + "sampler": "animation_0_rotation_sampler", + "target": { + "id": "Geometry-mesh001Node", + "path": "rotation" + } + } + ], + "parameters": { + "TIME": "animAccessor_0", + "rotation": "animAccessor_1" + }, + "samplers": { + "animation_0_rotation_sampler": { + "input": "TIME", + "interpolation": "LINEAR", + "output": "rotation" + } + } + }, + "animation_1": { + "channels": [ + { + "sampler": "animation_1_rotation_sampler", + "target": { + "id": "meshInst962Node", + "path": "rotation" + } + } + ], + "parameters": { + "TIME": "animAccessor_0", + "rotation": "animAccessor_1" + }, + "samplers": { + "animation_1_rotation_sampler": { + "input": "TIME", + "interpolation": "LINEAR", + "output": "rotation" + } + } + } + }, + "asset": { + "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", + "premultipliedAlpha": true, + "profile": { + "api": "WebGL", + "version": "1.0.2" + }, + "version": 1 + }, + "bufferViews": { + "bufferView_103": { + "buffer": "CesiumMilkTruck", + "byteLength": 620, + "byteOffset": 0 + }, + "bufferView_104": { + "buffer": "CesiumMilkTruck", + "byteLength": 17136, + "byteOffset": 620, + "target": 34963 + }, + "bufferView_105": { + "buffer": "CesiumMilkTruck", + "byteLength": 95296, + "byteOffset": 17756, + "target": 34962 + } + }, + "buffers": { + "CesiumMilkTruck": { + "byteLength": 113052, + "type": "arraybuffer", + "uri": "CesiumMilkTruck.bin" + } + }, + "images": { + "Image0001": { + "name": "Image0001", + "uri": "CesiumMilkTruck.png" + } + }, + "materials": { + "Effect-glass": { + "name": "glass", + "technique": "technique0", + "values": { + "diffuse": [ + 0, + 0.0405063, + 0.0212407, + 1 + ], + "shininess": 256, + "specular": [ + 0.65, + 0.65, + 0.65, + 1 + ] + } + }, + "Effect-truck": { + "name": "truck", + "technique": "technique1", + "values": { + "diffuse": "texture_Image0001", + "shininess": 256, + "specular": [ + 0.04, + 0.04, + 0.04, + 1 + ] + } + }, + "Effect-wheels": { + "name": "wheels", + "technique": "technique1", + "values": { + "diffuse": "texture_Image0001", + "shininess": 256, + "specular": [ + 0.04, + 0.04, + 0.04, + 1 + ] + } + }, + "Effect-window_trim": { + "name": "window_trim", + "technique": "technique0", + "values": { + "diffuse": [ + 0.064, + 0.064, + 0.064, + 1 + ], + "shininess": 256, + "specular": [ + 0.04, + 0.04, + 0.04, + 1 + ] + } + } + }, + "meshes": { + "Geometry-mesh001": { + "name": "Wheels", + "primitives": [ + { + "attributes": { + "NORMAL": "accessor_100", + "POSITION": "accessor_98", + "TEXCOORD_0": "accessor_102" + }, + "indices": "accessor_96", + "material": "Effect-wheels", + "mode": 4 + } + ] + }, + "Geometry-mesh002": { + "name": "Cesium_Milk_Truck", + "primitives": [ + { + "attributes": { + "NORMAL": "accessor_73", + "POSITION": "accessor_71", + "TEXCOORD_0": "accessor_75" + }, + "indices": "accessor_63", + "material": "Effect-truck", + "mode": 4 + }, + { + "attributes": { + "NORMAL": "accessor_73", + "POSITION": "accessor_71", + "TEXCOORD_0": "accessor_75" + }, + "indices": "accessor_66", + "material": "Effect-glass", + "mode": 4 + }, + { + "attributes": { + "NORMAL": "accessor_73", + "POSITION": "accessor_71", + "TEXCOORD_0": "accessor_75" + }, + "indices": "accessor_69", + "material": "Effect-window_trim", + "mode": 4 + } + ] + } + }, + "nodes": { + "Geometry-mesh001Node": { + "children": [], + "meshes": [ + "Geometry-mesh001" + ], + "name": "Wheels", + "rotation": [ + 0, + 0, + -0.0884856, + 0.996077 + ], + "scale": [ + 1, + 1, + 1 + ], + "translation": [ + 1.43267, + 0.427722, + -2.98023e-008 + ] + }, + "Geometry-mesh002Node": { + "children": [ + "Geometry-mesh001Node", + "meshInst962Node" + ], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + "meshes": [ + "Geometry-mesh002" + ], + "name": "Cesium_Milk_Truck" + }, + "groupLocator006Node": { + "children": [ + "txtrLocator003Node", + "txtrLocator013Node" + ], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + "name": "Texture_Group" + }, + "meshInst962Node": { + "children": [], + "meshes": [ + "Geometry-mesh001" + ], + "name": "Wheels__2_", + "rotation": [ + 0, + 0, + -0.0884856, + 0.996077 + ], + "scale": [ + 1, + 1, + 1 + ], + "translation": [ + -1.35233, + 0.427722, + -2.98023e-008 + ] + }, + "polyRender006": { + "children": [], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + "name": "Render" + }, + "txtrLocator003Node": { + "children": [], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + "name": "Cesium_Milk_Truck__2___Image___Texture_" + }, + "txtrLocator013Node": { + "children": [], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + "name": "Cesium_Milk_Truck__2___Image___2___Texture_" + } + }, + "programs": { + "program_0": { + "attributes": [ + "a_normal", + "a_position" + ], + "fragmentShader": "CesiumMilkTruck0FS", + "vertexShader": "CesiumMilkTruck0VS" + }, + "program_1": { + "attributes": [ + "a_normal", + "a_position", + "a_texcoord0" + ], + "fragmentShader": "CesiumMilkTruck1FS", + "vertexShader": "CesiumMilkTruck1VS" + } + }, + "samplers": { + "sampler_0": { + "magFilter": 9729, + "minFilter": 9987, + "wrapS": 10497, + "wrapT": 10497 + } + }, + "scene": "defaultScene", + "scenes": { + "defaultScene": { + "nodes": [ + "polyRender006", + "Geometry-mesh002Node", + "groupLocator006Node" + ] + } + }, + "shaders": { + "CesiumMilkTruck0FS": { + "type": 35632, + "uri": "CesiumMilkTruck0FS.glsl" + }, + "CesiumMilkTruck0VS": { + "type": 35633, + "uri": "CesiumMilkTruck0VS.glsl" + }, + "CesiumMilkTruck1FS": { + "type": 35632, + "uri": "CesiumMilkTruck1FS.glsl" + }, + "CesiumMilkTruck1VS": { + "type": 35633, + "uri": "CesiumMilkTruck1VS.glsl" + } + }, + "skins": {}, + "techniques": { + "technique0": { + "attributes": { + "a_normal": "normal", + "a_position": "position" + }, + "parameters": { + "diffuse": { + "type": 35666 + }, + "modelViewMatrix": { + "semantic": "MODELVIEW", + "type": 35676 + }, + "normal": { + "semantic": "NORMAL", + "type": 35665 + }, + "normalMatrix": { + "semantic": "MODELVIEWINVERSETRANSPOSE", + "type": 35675 + }, + "position": { + "semantic": "POSITION", + "type": 35665 + }, + "projectionMatrix": { + "semantic": "PROJECTION", + "type": 35676 + }, + "shininess": { + "type": 5126 + }, + "specular": { + "type": 35666 + } + }, + "program": "program_0", + "states": { + "enable": [ + 2929, + 2884 + ] + }, + "uniforms": { + "u_diffuse": "diffuse", + "u_modelViewMatrix": "modelViewMatrix", + "u_normalMatrix": "normalMatrix", + "u_projectionMatrix": "projectionMatrix", + "u_shininess": "shininess", + "u_specular": "specular" + } + }, + "technique1": { + "attributes": { + "a_normal": "normal", + "a_position": "position", + "a_texcoord0": "texcoord0" + }, + "parameters": { + "diffuse": { + "type": 35678 + }, + "modelViewMatrix": { + "semantic": "MODELVIEW", + "type": 35676 + }, + "normal": { + "semantic": "NORMAL", + "type": 35665 + }, + "normalMatrix": { + "semantic": "MODELVIEWINVERSETRANSPOSE", + "type": 35675 + }, + "position": { + "semantic": "POSITION", + "type": 35665 + }, + "projectionMatrix": { + "semantic": "PROJECTION", + "type": 35676 + }, + "shininess": { + "type": 5126 + }, + "specular": { + "type": 35666 + }, + "texcoord0": { + "semantic": "TEXCOORD_0", + "type": 35664 + } + }, + "program": "program_1", + "states": { + "enable": [ + 2929, + 2884 + ] + }, + "uniforms": { + "u_diffuse": "diffuse", + "u_modelViewMatrix": "modelViewMatrix", + "u_normalMatrix": "normalMatrix", + "u_projectionMatrix": "projectionMatrix", + "u_shininess": "shininess", + "u_specular": "specular" + } + } + }, + "textures": { + "texture_Image0001": { + "format": 6408, + "internalFormat": 6408, + "sampler": "sampler_0", + "source": "Image0001", + "target": 3553, + "type": 5121 + } + } +} \ No newline at end of file diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.png b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.png new file mode 100644 index 000000000..ba7a47c7f Binary files /dev/null and b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck.png differ diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0FS.glsl b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0FS.glsl new file mode 100644 index 000000000..6e928dc70 --- /dev/null +++ b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0FS.glsl @@ -0,0 +1,17 @@ +precision highp float; +varying vec3 v_normal; +uniform vec4 u_diffuse; +uniform vec4 u_specular; +uniform float u_shininess; +void main(void) { +vec3 normal = normalize(v_normal); +vec4 color = vec4(0., 0., 0., 0.); +vec4 diffuse = vec4(0., 0., 0., 1.); +vec4 specular; +diffuse = u_diffuse; +specular = u_specular; +diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.); +color.xyz += diffuse.xyz; +color = vec4(color.rgb * diffuse.a, diffuse.a); +gl_FragColor = color; +} diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0VS.glsl b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0VS.glsl new file mode 100644 index 000000000..9e3592280 --- /dev/null +++ b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck0VS.glsl @@ -0,0 +1,12 @@ +precision highp float; +attribute vec3 a_position; +attribute vec3 a_normal; +varying vec3 v_normal; +uniform mat3 u_normalMatrix; +uniform mat4 u_modelViewMatrix; +uniform mat4 u_projectionMatrix; +void main(void) { +vec4 pos = u_modelViewMatrix * vec4(a_position,1.0); +v_normal = u_normalMatrix * a_normal; +gl_Position = u_projectionMatrix * pos; +} diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1FS.glsl b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1FS.glsl new file mode 100644 index 000000000..782e1f416 --- /dev/null +++ b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1FS.glsl @@ -0,0 +1,18 @@ +precision highp float; +varying vec3 v_normal; +varying vec2 v_texcoord0; +uniform sampler2D u_diffuse; +uniform vec4 u_specular; +uniform float u_shininess; +void main(void) { +vec3 normal = normalize(v_normal); +vec4 color = vec4(0., 0., 0., 0.); +vec4 diffuse = vec4(0., 0., 0., 1.); +vec4 specular; +diffuse = texture2D(u_diffuse, v_texcoord0); +specular = u_specular; +diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.); +color.xyz += diffuse.xyz; +color = vec4(color.rgb * diffuse.a, diffuse.a); +gl_FragColor = color; +} diff --git a/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1VS.glsl b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1VS.glsl new file mode 100644 index 000000000..cacc9ed99 --- /dev/null +++ b/test/models/glTF/CesiumMilkTruck/CesiumMilkTruck1VS.glsl @@ -0,0 +1,15 @@ +precision highp float; +attribute vec3 a_position; +attribute vec3 a_normal; +varying vec3 v_normal; +uniform mat3 u_normalMatrix; +uniform mat4 u_modelViewMatrix; +uniform mat4 u_projectionMatrix; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main(void) { +vec4 pos = u_modelViewMatrix * vec4(a_position,1.0); +v_normal = u_normalMatrix * a_normal; +v_texcoord0 = a_texcoord0; +gl_Position = u_projectionMatrix * pos; +} diff --git a/test/regression/README.txt b/test/regression/README.txt index b0e79e1f8..aab4c1104 100644 --- a/test/regression/README.txt +++ b/test/regression/README.txt @@ -1,5 +1,5 @@ -Assimp Regression Test Suite -============================ +Asset Importer Lib Regression Test Suite +======================================== 1) How does it work? --------------------------------------------------------------------------------- diff --git a/test/regression/db.zip b/test/regression/db.zip index c94598840..575062e0e 100644 Binary files a/test/regression/db.zip and b/test/regression/db.zip differ diff --git a/test/regression/run.py b/test/regression/run.py index 4763ad9d3..12f0fc94d 100755 --- a/test/regression/run.py +++ b/test/regression/run.py @@ -9,34 +9,34 @@ # # All rights reserved. # -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the following +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the following # conditions are met: -# +# # * Redistributions of source code must retain the above # copyright notice, this list of conditions and the # following disclaimer. -# +# # * 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. -# +# # * Neither the name of the ASSIMP team, nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior # written permission of the ASSIMP Development Team. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# +# 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 +# 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 +# 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 +# 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. # --------------------------------------------------------------------------- @@ -98,7 +98,7 @@ outfilename_output = "run_regression_suite_output.txt" outfilename_failur = "run_regression_suite_failures.csv" # ------------------------------------------------------------------------------- class results: - + """ Handle formatting of results""" def __init__(self, zipin): @@ -106,15 +106,15 @@ class results: self.failures = [] self.success = [] self.zipin = zipin - - + + def fail(self, failfile, filename_expect, pp, msg, *args): """ Report failure of a sub-test - - File f failed a test for pp config pp, failure notice is msg, + + File f failed a test for pp config pp, failure notice is msg, *args is format()ting args for msg - + """ print("[FAILURE] " + messages[msg].format(*args)) self.failures.append((failfile, filename_expect, pp)) @@ -124,11 +124,11 @@ class results: """ Report success of a sub-test - File f passed the test, msg is a happy success note, + File f passed the test, msg is a happy success note, *args is format()ing args for msg. """ - print("[SUCCESS] " + messages[msg].format(*args)) + print("[SUCCESS] " + messages[msg].format(*args)) self.success.append(f) @@ -139,22 +139,22 @@ class results: count_fail = len(self.failures) percent_good = float(count_success) / (count_success + count_fail) print("\n" + ('='*60) + "\n" + "SUCCESS: {0}\nFAILURE: {1}\nPercentage good: {2}".format( - count_success, count_fail, percent_good) + + count_success, count_fail, percent_good) + "\n" + ('='*60) + "\n") with open(os.path.join('..', 'results',outfilename_failur), "wt") as f: f.write("ORIGINAL FILE;EXPECTED DUMP\n") f.writelines(map( lambda x: x[0] + ' ' + x[2] + ";" + x[1] + "\n", self.failures)) - + if self.failures: - print("\nSee " + settings.results + "\\" + outfilename_failur - + " for more details\n\n") - + print("\nSee " + settings.results + "\\" + outfilename_failur + + " for more details\n\n") + def hasFailures( self ): """ Return True, if any failures there. """ return 0 != len( self.failures ) - + # ------------------------------------------------------------------------------- def prepare_output_dir(fullpath, myhash, app): outfile = os.path.join(settings.results, "tmp", os.path.split(fullpath)[1] + "_" + myhash) @@ -162,7 +162,7 @@ def prepare_output_dir(fullpath, myhash, app): os.mkdir(outfile) except OSError: pass - + outfile = os.path.join(outfile, app) return outfile @@ -197,8 +197,8 @@ def process_dir(d, outfile_results, zipin, result): "regression database? Use gen_db.zip to re-generate.") continue - print("-"*60 + "\n " + os.path.realpath(fullpath) + " pp: " + pppreset) - + print("-"*60 + "\n " + os.path.realpath(fullpath) + " pp: " + pppreset) + outfile_actual = prepare_output_dir(fullpath, filehash, "ACTUAL") outfile_expect = prepare_output_dir(fullpath, filehash, "EXPECT") outfile_results.write("assimp dump "+"-"*80+"\n") @@ -219,19 +219,19 @@ def process_dir(d, outfile_results, zipin, result): outfile_results.write("Expected import to fail\n") continue elif failure and r: - result.ok(fullpath, pppreset, EXPECTED_FAILURE) + result.ok(fullpath, pppreset, EXPECTED_FAILURE) outfile_results.write("Failed as expected, skipping.\n") continue - - with open(outfile_expect, "wb") as s: - s.write(input_expected) - try: + with open(outfile_expect, "wb") as s: + s.write(input_expected) + + try: with open(outfile_actual, "rb") as s: - input_actual = s.read() + input_actual = s.read() except IOError: continue - + outfile_results.write("Expected data length: {0}\n".format(len(input_expected))) outfile_results.write("Actual data length: {0}\n".format(len(input_actual))) failed = False @@ -247,9 +247,9 @@ def process_dir(d, outfile_results, zipin, result): if subprocess.call(command, **shellparams) != 0: if not failed: result.fail(fullpath, outfile_expect, pppreset, DATABASE_VALUE_MISMATCH) - continue - - result.ok(fullpath, pppreset, COMPARE_SUCCESS, len(input_expected)) + continue + + result.ok(fullpath, pppreset, COMPARE_SUCCESS, len(input_expected)) # ------------------------------------------------------------------------------- def del_folder_with_contents(folder): @@ -258,13 +258,14 @@ def del_folder_with_contents(folder): os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) - + # ------------------------------------------------------------------------------- def run_test(): tmp_target_path = os.path.join(settings.results, "tmp") - try: - os.mkdir(tmp_target_path) + try: + print( "try to make " + tmp_target_path ) + os.mkdir(tmp_target_path) except OSError as oerr: # clear contents if tmp folder exists already del_folder_with_contents(tmp_target_path) @@ -272,7 +273,7 @@ def run_test(): try: zipin = zipfile.ZipFile(settings.database_name + ".zip", "r", zipfile.ZIP_STORED) - + except IOError: print("Regression database ", settings.database_name, ".zip was not found") @@ -286,13 +287,16 @@ def run_test(): res.report_results() if res.hasFailures(): return 1 - + return 0 - + # ------------------------------------------------------------------------------- if __name__ == "__main__": - assimp_bin_path = sys.argv[1] if len(sys.argv) > 1 else 'assimp' + if len(sys.argv) > 1: + assimp_bin_path = sys.argv[1] + else: + assimp_bin_path = 'assimp' print('Using assimp binary: ' + assimp_bin_path) sys.exit( run_test() ) diff --git a/test/unit/utColladaExportCamera.cpp b/test/unit/utColladaExportCamera.cpp index 8735c626e..684e545a9 100644 --- a/test/unit/utColladaExportCamera.cpp +++ b/test/unit/utColladaExportCamera.cpp @@ -1,11 +1,43 @@ /* - * ColladaCameraExporter.cpp - * - * Created on: May 17, 2015 - * Author: wise - */ +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- +Copyright (c) 2006-2014, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -49,31 +81,47 @@ TEST_F(ColladaExportCamera, testExportCamera) EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file)); - + const unsigned int origNumCams( pTest->mNumCameras ); + float *origFOV = new float[ origNumCams ]; + float *orifClipPlaneNear = new float[ origNumCams ]; + float *orifClipPlaneFar = new float[ origNumCams ]; + aiString *names = new aiString[ origNumCams ]; + aiVector3D *pos = new aiVector3D[ origNumCams ]; + for (size_t i = 0; i < origNumCams; i++) { + const aiCamera *orig = pTest->mCameras[ i ]; + origFOV[ i ] = orig->mHorizontalFOV; + orifClipPlaneNear[ i ] = orig->mClipPlaneNear; + orifClipPlaneFar[ i ] = orig->mClipPlaneFar; + names[ i ] = orig->mName; + pos[ i ] = orig->mPosition; + } const aiScene* imported = im->ReadFile(file,0); ASSERT_TRUE(imported!=NULL); - EXPECT_TRUE(imported->HasCameras()); - EXPECT_EQ(pTest->mNumCameras,imported->mNumCameras); + EXPECT_TRUE( imported->HasCameras() ); + EXPECT_EQ( origNumCams, imported->mNumCameras ); - for(size_t i=0; i< pTest->mNumCameras;i++){ + for(size_t i=0; i< imported->mNumCameras;i++){ + const aiCamera *read = imported->mCameras[ i ]; - const aiCamera *orig = pTest->mCameras[i]; - const aiCamera *read = imported->mCameras[i]; + EXPECT_TRUE( names[ i ] == read->mName ); + EXPECT_NEAR( origFOV[ i ],read->mHorizontalFOV, 0.0001f ); + EXPECT_FLOAT_EQ( orifClipPlaneNear[ i ], read->mClipPlaneNear); + EXPECT_FLOAT_EQ( orifClipPlaneFar[ i ], read->mClipPlaneFar); - EXPECT_TRUE(orig->mName==read->mName); - EXPECT_FLOAT_EQ(orig->mHorizontalFOV,read->mHorizontalFOV); - EXPECT_FLOAT_EQ(orig->mClipPlaneNear,read->mClipPlaneNear); - EXPECT_FLOAT_EQ(orig->mClipPlaneFar,read->mClipPlaneFar); - - EXPECT_FLOAT_EQ(orig->mPosition.x,read->mPosition.x); - EXPECT_FLOAT_EQ(orig->mPosition.y,read->mPosition.y); - EXPECT_FLOAT_EQ(orig->mPosition.z,read->mPosition.z); + EXPECT_FLOAT_EQ( pos[ i ].x,read->mPosition.x); + EXPECT_FLOAT_EQ( pos[ i ].y,read->mPosition.y); + EXPECT_FLOAT_EQ( pos[ i ].z,read->mPosition.z); } -} + delete [] origFOV; + delete [] orifClipPlaneNear; + delete [] orifClipPlaneFar; + delete [] names; + delete [] pos; +} #endif diff --git a/test/unit/utColladaExportLight.cpp b/test/unit/utColladaExportLight.cpp index ee17b77e0..5edf3e9c3 100644 --- a/test/unit/utColladaExportLight.cpp +++ b/test/unit/utColladaExportLight.cpp @@ -1,11 +1,43 @@ /* - * ColladaCameraExporter.cpp - * - * Created on: May 17, 2015 - * Author: wise - */ +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- +Copyright (c) 2006-2014, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -22,7 +54,6 @@ public: { ex = new Assimp::Exporter(); im = new Assimp::Importer(); - } virtual void TearDown() @@ -41,33 +72,39 @@ protected: // ------------------------------------------------------------------------------------------------ TEST_F(ColladaExportLight, testExportLight) { - const char* file = "cameraExp.dae"; + const char* file = "lightsExp.dae"; const aiScene* pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae",0); ASSERT_TRUE(pTest!=NULL); ASSERT_TRUE(pTest->HasLights()); + const unsigned int origNumLights( pTest->mNumLights ); + aiLight *origLights = new aiLight[ origNumLights ]; + std::vector origNames; + for (size_t i = 0; i < origNumLights; i++) { + origNames.push_back( pTest->mLights[ i ]->mName.C_Str() ); + origLights[ i ] = *(pTest->mLights[ i ]); + } EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file)); - EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada","lightsExp.dae")); const aiScene* imported = im->ReadFile(file,0); ASSERT_TRUE(imported!=NULL); EXPECT_TRUE(imported->HasLights()); - EXPECT_EQ(pTest->mNumLights,imported->mNumLights); + EXPECT_EQ( origNumLights,imported->mNumLights ); + for(size_t i=0; i< origNumLights; i++){ - for(size_t i=0; i< pTest->mNumLights;i++){ - - const aiLight *orig = pTest->mLights[i]; + const aiLight *orig = &origLights[ i ]; + const aiLight *read = imported->mLights[i]; - EXPECT_TRUE(orig->mName==read->mName); + EXPECT_EQ(0,strncmp(origNames[ i ].c_str(),read->mName.C_Str(), origNames[ i ].size() ) ); EXPECT_EQ(orig->mType,read->mType); EXPECT_FLOAT_EQ(orig->mAttenuationConstant,read->mAttenuationConstant); EXPECT_FLOAT_EQ(orig->mAttenuationLinear,read->mAttenuationLinear); - EXPECT_FLOAT_EQ(orig->mAttenuationQuadratic,read->mAttenuationQuadratic); + EXPECT_NEAR(orig->mAttenuationQuadratic,read->mAttenuationQuadratic, 0.001f); EXPECT_FLOAT_EQ(orig->mColorAmbient.r,read->mColorAmbient.r); EXPECT_FLOAT_EQ(orig->mColorAmbient.g,read->mColorAmbient.g); @@ -84,6 +121,9 @@ TEST_F(ColladaExportLight, testExportLight) EXPECT_NEAR(orig->mAngleInnerCone,read->mAngleInnerCone,0.001); EXPECT_NEAR(orig->mAngleOuterCone,read->mAngleOuterCone,0.001); } + + delete [] origLights; + } diff --git a/test/unit/utFastAtof.cpp b/test/unit/utFastAtof.cpp index 776317431..b95d4da5a 100644 --- a/test/unit/utFastAtof.cpp +++ b/test/unit/utFastAtof.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp index ef85a7bb0..9520a4804 100644 --- a/test/unit/utFindDegenerates.cpp +++ b/test/unit/utFindDegenerates.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utFindInvalidData.cpp b/test/unit/utFindInvalidData.cpp index 9a9bb1ca7..f9741c8ae 100644 --- a/test/unit/utFindInvalidData.cpp +++ b/test/unit/utFindInvalidData.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utFixInfacingNormals.cpp b/test/unit/utFixInfacingNormals.cpp index 21a83a64a..7e2e266b4 100644 --- a/test/unit/utFixInfacingNormals.cpp +++ b/test/unit/utFixInfacingNormals.cpp @@ -1 +1,41 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" diff --git a/test/unit/utGenNormals.cpp b/test/unit/utGenNormals.cpp index be6b5ee8b..8b6414fea 100644 --- a/test/unit/utGenNormals.cpp +++ b/test/unit/utGenNormals.cpp @@ -1,5 +1,44 @@ -#include "UnitTestPCH.h" +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index 0b300b9b4..1faa9ad70 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include "../../include/assimp/postprocess.h" diff --git a/test/unit/utImproveCacheLocality.cpp b/test/unit/utImproveCacheLocality.cpp index 5d0076b61..928be7275 100644 --- a/test/unit/utImproveCacheLocality.cpp +++ b/test/unit/utImproveCacheLocality.cpp @@ -1,2 +1,42 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" \ No newline at end of file diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp new file mode 100644 index 000000000..7346009ba --- /dev/null +++ b/test/unit/utIssues.cpp @@ -0,0 +1,109 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" + +#include +#include +#include + +using namespace Assimp; + +class utIssues : public ::testing::Test { + +}; + +#ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F( utIssues, OpacityBugWhenExporting_727 ) { + aiScene *scene( new aiScene ); + + scene->mNumMaterials = 1; + scene->mMaterials = new aiMaterial*; + scene->mMaterials[ 0 ] = new aiMaterial; + aiColor3D color( 1, 0, 0 ); + EXPECT_EQ( AI_SUCCESS, scene->mMaterials[ 0 ]->AddProperty( &color, 1, AI_MATKEY_COLOR_DIFFUSE ) ); + + ::srand( static_cast( ::time( NULL ) ) ); + float opacity( float( rand() ) / float( RAND_MAX ) ); + EXPECT_EQ( AI_SUCCESS, scene->mMaterials[ 0 ]->AddProperty( &opacity, 1, AI_MATKEY_OPACITY ) ); + + scene->mNumMeshes = 1; + scene->mMeshes = new aiMesh*; + scene->mMeshes[ 0 ] = new aiMesh; + scene->mMeshes[ 0 ]->mMaterialIndex = 0; + scene->mMeshes[ 0 ]->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + scene->mMeshes[ 0 ]->mNumVertices = 3; + scene->mMeshes[ 0 ]->mVertices = new aiVector3D[ 3 ]; + scene->mMeshes[ 0 ]->mVertices[ 0 ] = aiVector3D( 1, 0, 0 ); + scene->mMeshes[ 0 ]->mVertices[ 1 ] = aiVector3D( 0, 1, 0 ); + scene->mMeshes[ 0 ]->mVertices[ 2 ] = aiVector3D( 0, 0, 1 ); + scene->mMeshes[ 0 ]->mNumFaces = 1; + scene->mMeshes[ 0 ]->mFaces = new aiFace; + scene->mMeshes[ 0 ]->mFaces[ 0 ].mNumIndices = 3; + scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices = new unsigned int[ 3 ]; + scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 0 ] = 0; + scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 1 ] = 1; + scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 2 ] = 2; + + scene->mRootNode = new aiNode; + scene->mRootNode->mNumMeshes = 1; + scene->mRootNode->mMeshes = new unsigned int( 0 ); + + Assimp::Importer importer; + Assimp::Exporter exporter; + for ( std::size_t i( 0 ); i < exporter.GetExportFormatCount(); ++i ) { + /*const aiExportFormatDesc *desc( exporter.GetExportFormatDescription( i ) ); + std::cout << "[" << desc->id << "] "; + std::string path( "scene." ); + path.append( desc->fileExtension ); + + ASSERT_EQ( AI_SUCCESS, exporter.Export( scene, desc->id, path ) ); + const aiScene *newScene( importer.ReadFile( path, 0 ) ); + ASSERT_TRUE( NULL != newScene ); + float newOpacity; + if ( newScene->mNumMaterials > 0 ) { + //ASSERT_EQ( AI_SUCCESS, newScene->mMaterials[ 0 ]->Get( AI_MATKEY_OPACITY, newOpacity ) ); + //EXPECT_EQ( opacity, newOpacity ); + }*/ + } +} + +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/utJoinVertices.cpp b/test/unit/utJoinVertices.cpp index 1e7c3d08e..cbc68cf92 100644 --- a/test/unit/utJoinVertices.cpp +++ b/test/unit/utJoinVertices.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utLimitBoneWeights.cpp b/test/unit/utLimitBoneWeights.cpp index dfcb037b0..716aecec4 100644 --- a/test/unit/utLimitBoneWeights.cpp +++ b/test/unit/utLimitBoneWeights.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utMaterialSystem.cpp b/test/unit/utMaterialSystem.cpp index 836adcd75..c63469929 100644 --- a/test/unit/utMaterialSystem.cpp +++ b/test/unit/utMaterialSystem.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utMatrix4x4.cpp b/test/unit/utMatrix4x4.cpp new file mode 100644 index 000000000..43c6cbb48 --- /dev/null +++ b/test/unit/utMatrix4x4.cpp @@ -0,0 +1,93 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" + +using namespace Assimp; + +class utMatrix4x4Test : public ::testing::Test { + +}; + +TEST_F( utMatrix4x4Test, badIndexOperatorTest ) { + aiMatrix4x4 m; + float *a0 = m[ 4 ]; + EXPECT_EQ( NULL, a0 ); +} + +TEST_F( utMatrix4x4Test, indexOperatorTest ) { + aiMatrix4x4 m; + float *a0 = m[ 0 ]; + EXPECT_FLOAT_EQ( 1.0f, *a0 ); + float *a1 = a0+1; + EXPECT_FLOAT_EQ( 0.0f, *a1 ); + float *a2 = a0 + 2; + EXPECT_FLOAT_EQ( 0.0f, *a2 ); + float *a3 = a0 + 3; + EXPECT_FLOAT_EQ( 0.0f, *a3 ); + + float *a4 = m[ 1 ]; + EXPECT_FLOAT_EQ( 0.0f, *a4 ); + float *a5 = a4 + 1; + EXPECT_FLOAT_EQ( 1.0f, *a5 ); + float *a6 = a4 + 2; + EXPECT_FLOAT_EQ( 0.0f, *a6 ); + float *a7 = a4 + 3; + EXPECT_FLOAT_EQ( 0.0f, *a7 ); + + float *a8 = m[ 2 ]; + EXPECT_FLOAT_EQ( 0.0f, *a8 ); + float *a9 = a8 + 1; + EXPECT_FLOAT_EQ( 0.0f, *a9 ); + float *a10 = a8 + 2; + EXPECT_FLOAT_EQ( 1.0f, *a10 ); + float *a11 = a8 + 3; + EXPECT_FLOAT_EQ( 0.0f, *a11 ); + + float *a12 = m[ 3 ]; + EXPECT_FLOAT_EQ( 0.0f, *a12 ); + float *a13 = a12 + 1; + EXPECT_FLOAT_EQ( 0.0f, *a13 ); + float *a14 = a12 + 2; + EXPECT_FLOAT_EQ( 0.0f, *a14 ); + float *a15 = a12 + 3; + EXPECT_FLOAT_EQ( 1.0f, *a15 ); +} \ No newline at end of file diff --git a/test/unit/utNoBoostTest.cpp b/test/unit/utNoBoostTest.cpp index a8c2f1567..906ff639a 100644 --- a/test/unit/utNoBoostTest.cpp +++ b/test/unit/utNoBoostTest.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include "BoostWorkaround/boost/tuple/tuple.hpp" @@ -36,12 +76,13 @@ TEST(NoBoostTest, Tuple) { EXPECT_EQ(4U, first.get<1>()); EXPECT_EQ(4U, first.get<2>()); - boost::tuple second; + boost::tuple second= + boost::make_tuple(1,1.0f,0.0,false,another()); bool b = second.get<3>(); - EXPECT_FALSE(b); - // check empty tuple, ignore compile warning + // check empty tuple boost::tuple<> third; + third; // FIXME: Explicit conversion not really required yet boost::tuple last = diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index 88fdd15af..318478aae 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -7,10 +47,8 @@ using namespace std; using namespace Assimp; -class PretransformVerticesTest : public ::testing::Test -{ +class PretransformVerticesTest : public ::testing::Test { public: - virtual void SetUp(); virtual void TearDown(); diff --git a/test/unit/utRemoveComments.cpp b/test/unit/utRemoveComments.cpp index f0977f374..96570804b 100644 --- a/test/unit/utRemoveComments.cpp +++ b/test/unit/utRemoveComments.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -15,9 +55,9 @@ TEST(RemoveCommentsTest, testSingleLineComments) "\ttrue) { // do something here \n" "\t// hello ... and bye //\n"; - - char* szTest2 = new char[::strlen(szTest)+1]; - ::strcpy(szTest2,szTest); + const size_t len( ::strlen( szTest ) + 1 ); + char* szTest2 = new char[ len ]; + ::strncpy( szTest2, szTest, len ); const char* szTestResult = "int i = 0; \n" "if (4 == \n" @@ -45,8 +85,9 @@ TEST(RemoveCommentsTest, testMultiLineComments) " " " / * Incomplete comment */ */"; - char* szTest2 = new char[::strlen(szTest)+1]; - ::strcpy(szTest2,szTest); + const size_t len( ::strlen( szTest ) + 1 ); + char* szTest2 = new char[ len ]; + ::strncpy( szTest2, szTest, len ); CommentRemover::RemoveMultiLineComments("/*","*/",szTest2,' '); EXPECT_STREQ(szTestResult, szTest2); diff --git a/test/unit/utRemoveComponent.cpp b/test/unit/utRemoveComponent.cpp index c807a918c..cc5dc4add 100644 --- a/test/unit/utRemoveComponent.cpp +++ b/test/unit/utRemoveComponent.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utRemoveRedundantMaterials.cpp b/test/unit/utRemoveRedundantMaterials.cpp index 769308246..e660a34fa 100644 --- a/test/unit/utRemoveRedundantMaterials.cpp +++ b/test/unit/utRemoveRedundantMaterials.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -20,7 +60,6 @@ protected: RemoveRedundantMatsProcess* piProcess; aiScene* pcScene1; - aiScene* pcScene2; }; // ------------------------------------------------------------------------------------------------ diff --git a/test/unit/utScenePreprocessor.cpp b/test/unit/utScenePreprocessor.cpp index 3115d3335..c60c07ffa 100644 --- a/test/unit/utScenePreprocessor.cpp +++ b/test/unit/utScenePreprocessor.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utSharedPPData.cpp b/test/unit/utSharedPPData.cpp index cf4f9fcc8..73172166c 100644 --- a/test/unit/utSharedPPData.cpp +++ b/test/unit/utSharedPPData.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -19,28 +59,16 @@ protected: SharedPostProcessInfo* shared; }; -static bool destructed; - -struct TestType -{ - ~TestType() - { - destructed = true; - } -}; - - // ------------------------------------------------------------------------------------------------ void SharedPPDataTest::SetUp() { shared = new SharedPostProcessInfo(); - destructed = false; } // ------------------------------------------------------------------------------------------------ void SharedPPDataTest::TearDown() { - + delete shared; } // ------------------------------------------------------------------------------------------------ @@ -72,14 +100,26 @@ TEST_F(SharedPPDataTest, testPropertyPointer) EXPECT_FALSE(shared->GetProperty("test16",o)); } +static bool destructed; + +struct TestType +{ + ~TestType() + { + destructed = true; + } +}; // ------------------------------------------------------------------------------------------------ TEST_F(SharedPPDataTest, testPropertyDeallocation) { - TestType *out, * pip = new TestType(); - shared->AddProperty("quak",pip); - EXPECT_TRUE(shared->GetProperty("quak",out)); + SharedPostProcessInfo* localShared = new SharedPostProcessInfo(); + destructed = false; + + TestType *out, * pip = new TestType(); + localShared->AddProperty("quak",pip); + EXPECT_TRUE(localShared->GetProperty("quak",out)); EXPECT_EQ(pip, out); - delete shared; + delete localShared; EXPECT_TRUE(destructed); } diff --git a/test/unit/utSortByPType.cpp b/test/unit/utSortByPType.cpp index c412905ec..cefda1c63 100644 --- a/test/unit/utSortByPType.cpp +++ b/test/unit/utSortByPType.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utSplitLargeMeshes.cpp b/test/unit/utSplitLargeMeshes.cpp index e116d7f1f..0814f2932 100644 --- a/test/unit/utSplitLargeMeshes.cpp +++ b/test/unit/utSplitLargeMeshes.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include @@ -18,8 +58,7 @@ protected: SplitLargeMeshesProcess_Triangle* piProcessTriangle; SplitLargeMeshesProcess_Vertex* piProcessVertex; - aiMesh* pcMesh1; - aiMesh* pcMesh2; + }; // ------------------------------------------------------------------------------------------------ @@ -32,44 +71,6 @@ void SplitLargeMeshesTest::SetUp() this->piProcessTriangle->SetLimit(1000); this->piProcessVertex->SetLimit(1000); - this->pcMesh1 = new aiMesh(); - pcMesh1->mNumVertices = 2100; // quersumme: 3 - pcMesh1->mVertices = new aiVector3D[pcMesh1->mNumVertices]; - pcMesh1->mNormals = new aiVector3D[pcMesh1->mNumVertices]; - - pcMesh1->mNumFaces = pcMesh1->mNumVertices / 3; - pcMesh1->mFaces = new aiFace[pcMesh1->mNumFaces]; - - unsigned int qq = 0; - for (unsigned int i = 0; i < pcMesh1->mNumFaces;++i) - { - aiFace& face = pcMesh1->mFaces[i]; - face.mNumIndices = 3; - face.mIndices = new unsigned int[3]; - face.mIndices[0] = qq++; - face.mIndices[1] = qq++; - face.mIndices[2] = qq++; - } - - // generate many, many faces with randomized indices for - // the second mesh - this->pcMesh2 = new aiMesh(); - pcMesh2->mNumVertices = 3000; - pcMesh2->mVertices = new aiVector3D[pcMesh2->mNumVertices]; - pcMesh2->mNormals = new aiVector3D[pcMesh2->mNumVertices]; - - pcMesh2->mNumFaces = 10000; - pcMesh2->mFaces = new aiFace[pcMesh2->mNumFaces]; - - for (unsigned int i = 0; i < pcMesh2->mNumFaces;++i) - { - aiFace& face = pcMesh2->mFaces[i]; - face.mNumIndices = 3; - face.mIndices = new unsigned int[3]; - face.mIndices[0] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); - face.mIndices[1] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); - face.mIndices[2] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); - } } // ------------------------------------------------------------------------------------------------ @@ -84,6 +85,26 @@ TEST_F(SplitLargeMeshesTest, testVertexSplit) { std::vector< std::pair > avOut; + aiMesh *pcMesh1 = new aiMesh(); + pcMesh1->mNumVertices = 2100; // quersumme: 3 + pcMesh1->mVertices = new aiVector3D[pcMesh1->mNumVertices]; + pcMesh1->mNormals = new aiVector3D[pcMesh1->mNumVertices]; + + pcMesh1->mNumFaces = pcMesh1->mNumVertices / 3; + pcMesh1->mFaces = new aiFace[pcMesh1->mNumFaces]; + + unsigned int qq = 0; + for (unsigned int i = 0; i < pcMesh1->mNumFaces;++i) + { + aiFace& face = pcMesh1->mFaces[i]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = qq++; + face.mIndices[1] = qq++; + face.mIndices[2] = qq++; + } + + int iOldFaceNum = (int)pcMesh1->mNumFaces; piProcessVertex->SplitMesh(0,pcMesh1,avOut); @@ -107,6 +128,26 @@ TEST_F(SplitLargeMeshesTest, testTriangleSplit) { std::vector< std::pair > avOut; + // generate many, many faces with randomized indices for + // the second mesh + aiMesh *pcMesh2 = new aiMesh(); + pcMesh2->mNumVertices = 3000; + pcMesh2->mVertices = new aiVector3D[pcMesh2->mNumVertices]; + pcMesh2->mNormals = new aiVector3D[pcMesh2->mNumVertices]; + + pcMesh2->mNumFaces = 10000; + pcMesh2->mFaces = new aiFace[pcMesh2->mNumFaces]; + + for (unsigned int i = 0; i < pcMesh2->mNumFaces;++i) + { + aiFace& face = pcMesh2->mFaces[i]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); + face.mIndices[1] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); + face.mIndices[2] = (unsigned int)((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices); + } + // the number of faces shouldn't change int iOldFaceNum = (int)pcMesh2->mNumFaces; piProcessTriangle->SplitMesh(0,pcMesh2,avOut); diff --git a/test/unit/utTargetAnimation.cpp b/test/unit/utTargetAnimation.cpp index 1f799a276..7d797770e 100644 --- a/test/unit/utTargetAnimation.cpp +++ b/test/unit/utTargetAnimation.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" // TODO diff --git a/test/unit/utTextureTransform.cpp b/test/unit/utTextureTransform.cpp index 1f799a276..7d797770e 100644 --- a/test/unit/utTextureTransform.cpp +++ b/test/unit/utTextureTransform.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" // TODO diff --git a/test/unit/utTriangulate.cpp b/test/unit/utTriangulate.cpp index a8dfa5b8c..adffe687a 100644 --- a/test/unit/utTriangulate.cpp +++ b/test/unit/utTriangulate.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include diff --git a/test/unit/utVertexTriangleAdjacency.cpp b/test/unit/utVertexTriangleAdjacency.cpp index befa937cf..2629d67aa 100644 --- a/test/unit/utVertexTriangleAdjacency.cpp +++ b/test/unit/utVertexTriangleAdjacency.cpp @@ -1,3 +1,43 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* 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. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +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 "UnitTestPCH.h" #include "assimp/types.h" diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp index 8739c9364..f559790f6 100644 --- a/tools/assimp_cmd/CompareDump.cpp +++ b/tools/assimp_cmd/CompareDump.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -881,7 +881,7 @@ int Assimp_CompareDump (const char* const* params, unsigned int num) } // assimp cmpdump actual expected - if (num < 1) { + if (num < 2) { std::cout << "assimp cmpdump: Invalid number of arguments. " "See \'assimp cmpdump --help\'\r\n" << std::endl; return 1; diff --git a/tools/assimp_cmd/Export.cpp b/tools/assimp_cmd/Export.cpp index 560548a90..d83f5272a 100644 --- a/tools/assimp_cmd/Export.cpp +++ b/tools/assimp_cmd/Export.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp index cfcb01b07..7e7b9b439 100644 --- a/tools/assimp_cmd/ImageExtractor.cpp +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index b2a710284..41620b739 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 661e5d224..cb6f32834 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -291,7 +291,7 @@ const aiScene* ImportModel( PrintHorBar(); } if (!scene) { - printf("ERROR: Failed to load file\n"); + printf("ERROR: Failed to load file: %s\n", globalImporter->GetErrorString()); return NULL; } diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index bcdd64b3a..6a8ea3007 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. diff --git a/tools/assimp_view/Background.cpp b/tools/assimp_view/Background.cpp index 27f2f1546..9737e585e 100644 --- a/tools/assimp_view/Background.cpp +++ b/tools/assimp_view/Background.cpp @@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "assimp_view.h" +#include "StringUtils.h" namespace AssimpView { @@ -385,7 +386,7 @@ void CBackgroundPainter::RecreateNativeResource() if (!szEnd)szEnd = szPath.c_str()-1; char szTemp[1024]; - sprintf(szTemp,"[ERROR] Unable to load background cubemap %s",szEnd+1); + ai_snprintf(szTemp,1024,"[ERROR] Unable to load background cubemap %s",szEnd+1); CLogDisplay::Instance().AddEntry(szTemp, D3DCOLOR_ARGB(0xFF,0xFF,0,0)); @@ -419,7 +420,7 @@ void CBackgroundPainter::RecreateNativeResource() if (!szEnd)szEnd = szPath.c_str()-1; char szTemp[1024]; - sprintf(szTemp,"[ERROR] Unable to load background texture %s",szEnd+1); + ai_snprintf(szTemp,1024,"[ERROR] Unable to load background texture %s",szEnd+1); CLogDisplay::Instance().AddEntry(szTemp, D3DCOLOR_ARGB(0xFF,0xFF,0,0)); diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 69bcdb7c1..28c1550f3 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" #include "AnimEvaluator.h" #include "SceneAnimator.h" +#include "StringUtils.h" namespace AssimpView { @@ -168,13 +169,14 @@ int CDisplay::AddNodeToDisplayList( { iIndex += iDepth * 100; } - else iIndex += iDepth * 10; - sprintf(chTemp,"Node %u",iIndex); + else + iIndex += iDepth * 10; + ai_snprintf(chTemp, MAXLEN,"Node %u",iIndex); } else { - sprintf(chTemp,"%s",pcNode->mName.data); + ai_snprintf(chTemp, MAXLEN,"%s",pcNode->mName.data); } - sprintf(chTemp+strlen(chTemp), iIndex ? " (%i)" : " (%i meshes)",pcNode->mNumMeshes); + ai_snprintf(chTemp+strlen(chTemp), MAXLEN- strlen(chTemp), iIndex ? " (%i)" : " (%i meshes)",pcNode->mNumMeshes); TVITEMEXW tvi; TVINSERTSTRUCTW sNew; @@ -222,12 +224,12 @@ int CDisplay::AddMeshToDisplayList(unsigned int iIndex, HTREEITEM hRoot) char chTemp[MAXLEN]; if(0 == pcMesh->mName.length) { - sprintf(chTemp,"Mesh %u",iIndex); + ai_snprintf(chTemp,MAXLEN,"Mesh %u",iIndex); } else { - sprintf(chTemp,"%s",pcMesh->mName.data); + ai_snprintf(chTemp,MAXLEN,"%s",pcMesh->mName.data); } - sprintf(chTemp+strlen(chTemp), iIndex ? " (%i)" : " (%i faces)",pcMesh->mNumFaces); + ai_snprintf(chTemp+strlen(chTemp),MAXLEN-strlen(chTemp), iIndex ? " (%i)" : " (%i faces)",pcMesh->mNumFaces); TVITEMEXW tvi; TVINSERTSTRUCTW sNew; @@ -387,7 +389,7 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType, if ('*' == *szPath->data) { int iIndex = atoi(szPath->data+1); - sprintf(chTempEmb,"Embedded #%i",iIndex); + ai_snprintf(chTempEmb,256,"Embedded #%i",iIndex); sz = chTempEmb; } else @@ -451,10 +453,10 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType, break; }; if (bIsExtraOpacity) { - sprintf(chTemp,"%s %i ()",szType,iIndex+1); + ai_snprintf(chTemp,512,"%s %i ()",szType,iIndex+1); } else - sprintf(chTemp,"%s %i (%s)",szType,iIndex+1,sz); + ai_snprintf(chTemp,512,"%s %i (%s)",szType,iIndex+1,sz); TVITEMEX tvi; TVINSERTSTRUCT sNew; @@ -540,11 +542,11 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, aiString szOut; if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut)) { - sprintf(chTemp,"Material %i",iIndex+1); + ai_snprintf(chTemp,512,"Material %i",iIndex+1); } else { - sprintf(chTemp,"%s (%i)",szOut.data,iIndex+1); + ai_snprintf(chTemp,512,"%s (%i)",szOut.data,iIndex+1); } TVITEMEXW tvi; TVINSERTSTRUCTW sNew; @@ -821,24 +823,24 @@ int CDisplay::FillDefaultStatistics(void) } // and fill the statistic edit controls char szOut[1024]; - sprintf(szOut,"%i",(int)iNumVert); + ai_snprintf(szOut,1024,"%i",(int)iNumVert); SetDlgItemText(g_hDlg,IDC_EVERT,szOut); - sprintf(szOut,"%i",(int)iNumFaces); + ai_snprintf(szOut, 1024,"%i",(int)iNumFaces); SetDlgItemText(g_hDlg,IDC_EFACE,szOut); - sprintf(szOut,"%i",(int)g_pcAsset->pcScene->mNumMaterials); + ai_snprintf(szOut, 1024,"%i",(int)g_pcAsset->pcScene->mNumMaterials); SetDlgItemText(g_hDlg,IDC_EMAT,szOut); - sprintf(szOut,"%i",(int)g_pcAsset->pcScene->mNumMeshes); + ai_snprintf(szOut, 1024,"%i",(int)g_pcAsset->pcScene->mNumMeshes); SetDlgItemText(g_hDlg,IDC_EMESH,szOut); // need to get the number of nodes iNumVert = 0; GetNodeCount(g_pcAsset->pcScene->mRootNode,&iNumVert); - sprintf(szOut,"%i",(int)iNumVert); + ai_snprintf(szOut, 1024,"%i",(int)iNumVert); SetDlgItemText(g_hDlg,IDC_ENODEWND,szOut); // now get the number of unique shaders generated for the asset // (even if the environment changes this number won't change) - sprintf(szOut,"%i", CMaterialManager::Instance().GetShaderCount()); + ai_snprintf(szOut, 1024,"%i", CMaterialManager::Instance().GetShaderCount()); SetDlgItemText(g_hDlg,IDC_ESHADER,szOut); sprintf(szOut,"%.5f",(float)g_fLoadTime); diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index c3222299f..80cd3425f 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" +#include "StringUtils.h" #include using namespace std; @@ -257,8 +258,9 @@ int LoadAsset(void) g_pcAsset->mAnimator = new SceneAnimator( g_pcAsset->pcScene); // build a new caption string for the viewer - char szOut[MAX_PATH + 10]; - sprintf(szOut,AI_VIEW_CAPTION_BASE " [%s]",g_szFileName); + static const size_t Size = MAX_PATH + 10; + char szOut[Size]; + ai_snprintf(szOut, Size,AI_VIEW_CAPTION_BASE " [%s]",g_szFileName); SetWindowText(g_hDlg,szOut); // scale the asset vertices to fit into the viewer window