Ver código fonte

Merge pull request #13 from assimp/master

Update fork
Madrich 8 anos atrás
pai
commit
ae0850b88c
95 arquivos alterados com 5083 adições e 908 exclusões
  1. 3 6
      .travis.yml
  2. 0 2
      CMakeLists.txt
  3. 8 8
      Readme.md
  4. 1 1
      code/3DSExporter.cpp
  5. 1 1
      code/AMFImporter_Postprocess.cpp
  6. 4 0
      code/ASELoader.cpp
  7. 4 3
      code/ASELoader.h
  8. 3 0
      code/ASEParser.cpp
  9. 4 0
      code/ASEParser.h
  10. 36 0
      code/AssbinExporter.cpp
  11. 37 0
      code/AssbinLoader.cpp
  12. 2 1
      code/AssimpCExport.cpp
  13. 0 5
      code/BaseImporter.cpp
  14. 1 4
      code/BlenderDNA.h
  15. 3 3
      code/BlenderModifier.cpp
  16. 6 1
      code/CMakeLists.txt
  17. 1 1
      code/ColladaExporter.cpp
  18. 5 7
      code/ColladaLoader.cpp
  19. 4 4
      code/ColladaParser.cpp
  20. 6 5
      code/Exporter.cpp
  21. 3 4
      code/FBXBinaryTokenizer.cpp
  22. 40 17
      code/FBXConverter.cpp
  23. 2 2
      code/FBXDocument.cpp
  24. 5 0
      code/FBXImportSettings.h
  25. 1 0
      code/FBXImporter.cpp
  26. 29 24
      code/FBXMaterial.cpp
  27. 1 1
      code/FBXMeshGeometry.cpp
  28. 12 0
      code/FBXParser.h
  29. 1818 0
      code/FIReader.cpp
  30. 172 0
      code/FIReader.hpp
  31. 2 3
      code/HalfLifeFileData.h
  32. 1 1
      code/IRRLoader.cpp
  33. 1 1
      code/IRRLoader.h
  34. 2 0
      code/ImporterRegistry.cpp
  35. 2 1
      code/LWOAnimation.cpp
  36. 3 4
      code/LWOAnimation.h
  37. 1 1
      code/LWSLoader.cpp
  38. 1 1
      code/LWSLoader.h
  39. 12 15
      code/MD3FileData.h
  40. 1 1
      code/MD3Loader.cpp
  41. 1 1
      code/MDCFileData.h
  42. 51 76
      code/MDLFileData.h
  43. 12 23
      code/ObjFileParser.cpp
  44. 4 4
      code/OgreParsingUtils.h
  45. 1 1
      code/OptimizeGraph.cpp
  46. 1 1
      code/OptimizeMeshes.cpp
  47. 3 0
      code/PlyLoader.cpp
  48. 5 24
      code/PlyParser.cpp
  49. 1 1
      code/PretransformVertices.cpp
  50. 1 1
      code/SceneCombiner.cpp
  51. 2 1
      code/StepExporter.cpp
  52. 1 1
      code/Subdivision.cpp
  53. 2 2
      code/X3DExporter.cpp
  54. 2 2
      code/X3DExporter.hpp
  55. 211 222
      code/X3DImporter.cpp
  56. 14 21
      code/X3DImporter.hpp
  57. 11 11
      code/X3DImporter_Geometry3D.cpp
  58. 8 8
      code/X3DImporter_Metadata.cpp
  59. 28 5
      code/X3DImporter_Networking.cpp
  60. 14 13
      code/X3DImporter_Node.hpp
  61. 117 22
      code/X3DImporter_Rendering.cpp
  62. 1675 0
      code/X3DVocabulary.cpp
  63. 2 1
      code/XFileExporter.cpp
  64. 2 1
      code/XFileImporter.cpp
  65. 4 7
      code/XFileParser.cpp
  66. 5 2
      code/glTFExporter.cpp
  67. 114 8
      contrib/openddlparser/CMakeLists.txt
  68. 3 0
      contrib/openddlparser/CREDITS
  69. 2 2
      contrib/openddlparser/README.md
  70. 14 6
      contrib/openddlparser/code/DDLNode.cpp
  71. 35 9
      contrib/openddlparser/code/OpenDDLCommon.cpp
  72. 1 55
      contrib/openddlparser/code/OpenDDLExport.cpp
  73. 80 65
      contrib/openddlparser/code/OpenDDLParser.cpp
  74. 96 0
      contrib/openddlparser/code/OpenDDLStream.cpp
  75. 17 18
      contrib/openddlparser/code/Value.cpp
  76. 19 10
      contrib/openddlparser/include/openddlparser/DDLNode.h
  77. 3 4
      contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
  78. 3 27
      contrib/openddlparser/include/openddlparser/OpenDDLExport.h
  79. 11 1
      contrib/openddlparser/include/openddlparser/OpenDDLParser.h
  80. 36 8
      contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
  81. 89 0
      contrib/openddlparser/include/openddlparser/OpenDDLStream.h
  82. 7 3
      contrib/openddlparser/include/openddlparser/Value.h
  83. 0 2
      include/assimp/SceneCombiner.h
  84. 10 3
      include/assimp/config.h.in
  85. 16 4
      include/assimp/material.inl
  86. 94 94
      port/PyAssimp/README.md
  87. 1 1
      port/PyAssimp/scripts/3d_viewer.py
  88. 1 1
      port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py
  89. 1 1
      port/PyAssimp/scripts/sample.py
  90. 2 2
      port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake
  91. 4 0
      test/unit/ut3DSImportExport.cpp
  92. 4 0
      test/unit/utASEImportExport.cpp
  93. 1 0
      test/unit/utBatchLoader.cpp
  94. 1 1
      test/unit/utObjTools.cpp
  95. 2 4
      test/unit/utglTFImportExport.cpp

+ 3 - 6
.travis.yml

@@ -2,7 +2,7 @@ sudo: required
 language: cpp
 
 before_install:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
   - if [ "$TRAVIS_OS_NAME" =   "osx" ]; then brew install cmake python3 homebrew/x11/freeglut; fi
   - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
   # install latest LCOV (1.9 was failing)
@@ -16,6 +16,7 @@ osx_image: xcode8.3
 
 env:
   global:
+  # COVERITY_SCAN_TOKEN
     - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
     - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
   matrix:
@@ -23,11 +24,7 @@ env:
     - LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
     - LINUX=1 SHARED_BUILD=ON      ENABLE_COVERALLS=OFF
     - LINUX=1 SHARED_BUILD=OFF     ENABLE_COVERALLS=OFF
-    #exclude:
-    #    - os: linux
-    #      compiler: clang
-    #    - os: osx
-    #      compiler: gcc  
+
 compiler:
   - gcc
   - clang

+ 0 - 2
CMakeLists.txt

@@ -78,12 +78,10 @@ OPTION ( ASSIMP_COVERALLS
    "Eańable this to measure test coverage."
    OFF
 )
-
 option ( SYSTEM_IRRXML
     "Use system installed Irrlicht/IrrXML library."
     OFF
 )
-
 OPTION ( BUILD_DOCS
    "Build documentation using Doxygen."
    OFF

+ 8 - 8
Readme.md

@@ -1,6 +1,6 @@
 Open Asset Import Library (assimp)
 ==================================
-
+### Current build status ###
 [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
 [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
 <a href="https://scan.coverity.com/projects/5607">
@@ -9,22 +9,19 @@ Open Asset Import Library (assimp)
 </a>
 <span class="badge-patreon"><a href="https://www.patreon.com/assimp" title="Donate to this project using Patreon"><img src="https://img.shields.io/badge/patreon-donate-yellow.svg" alt="Patreon donate button" /></a></span>
 [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master)
+[![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 <br>
 
 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.
 
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 
-This is the development trunk containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories.
-The current build status is:
-
-Gitter chat: [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
+This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
 
-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
+One-off donations via PayPal:
+<br>[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
 
 <br>
-__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__
 
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
@@ -100,6 +97,9 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 
+### Other tools ###
+[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
+
 #### Repository structure ####
 Open Asset Import Library is implemented in C++. The directory structure is:
 

+ 1 - 1
code/3DSExporter.cpp

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3DSExporter.h"
 #include "3DSLoader.h"
 #include "3DSHelper.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "SplitLargeMeshes.h"
 #include "StringComparison.h"
 #include <assimp/IOSystem.hpp>

+ 1 - 1
code/AMFImporter_Postprocess.cpp

@@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AMFImporter.hpp"
 
 // Header files, Assimp.
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "StandardShapes.h"
 #include "StringUtils.h"
 

+ 4 - 0
code/ASELoader.cpp

@@ -46,6 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
 
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
+
 // internal headers
 #include "ASELoader.h"
 #include "StringComparison.h"
@@ -1320,4 +1322,6 @@ bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)  {
     return false;
 }
 
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
+
 #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER

+ 4 - 3
code/ASELoader.h

@@ -53,6 +53,7 @@ struct aiNode;
 
 namespace Assimp {
 
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 // --------------------------------------------------------------------------------
 /** Importer class for the 3DS ASE ASCII format.
@@ -63,9 +64,6 @@ public:
     ASEImporter();
     ~ASEImporter();
 
-
-public:
-
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details.
@@ -201,6 +199,9 @@ protected:
     bool noSkeletonMesh;
 };
 
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
+
 } // end of namespace Assimp
 
+
 #endif // AI_3DSIMPORTER_H_INC

+ 3 - 0
code/ASEParser.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 // internal headers
 #include "TextureTransform.h"
@@ -2151,4 +2152,6 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut)
     iOut = strtoul10(filePtr,&filePtr);
 }
 
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
+
 #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER

+ 4 - 0
code/ASEParser.h

@@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/mesh.h>
 #include <assimp/anim.h>
 
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
+
 // for some helper routines like IsSpace()
 #include "ParsingUtils.h"
 #include "qnan.h"
@@ -662,4 +664,6 @@ public:
 } // Namespace ASE
 } // Namespace ASSIMP
 
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
+
 #endif // !! include guard

+ 36 - 0
code/AssbinExporter.cpp

@@ -325,10 +325,13 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
         {
             AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
 
+			size_t nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
+
             Write<aiString>(&chunk,node->mName);
             Write<aiMatrix4x4>(&chunk,node->mTransformation);
             Write<unsigned int>(&chunk,node->mNumChildren);
             Write<unsigned int>(&chunk,node->mNumMeshes);
+			Write<unsigned int>(&chunk,nb_metadata);
 
             for (unsigned int i = 0; i < node->mNumMeshes;++i) {
                 Write<unsigned int>(&chunk,node->mMeshes[i]);
@@ -337,6 +340,39 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
             for (unsigned int i = 0; i < node->mNumChildren;++i) {
                 WriteBinaryNode( &chunk, node->mChildren[i] );
             }
+
+			for (unsigned int i = 0; i < nb_metadata; ++i) {
+				const aiString& key = node->mMetaData->mKeys[i];
+				aiMetadataType type = node->mMetaData->mValues[i].mType;
+				void* value = node->mMetaData->mValues[i].mData;
+
+				Write<aiString>(&chunk, key);
+				Write<uint16_t>(&chunk, type);
+				
+				switch (type) {
+				case AI_BOOL:
+					Write<bool>(&chunk, *((bool*) value));
+					break;
+				case AI_INT32:
+					Write<int32_t>(&chunk, *((int32_t*) value));
+					break;
+				case AI_UINT64:
+					Write<uint64_t>(&chunk, *((uint64_t*) value));
+					break;
+				case AI_FLOAT:
+					Write<float>(&chunk, *((float*) value));
+					break;
+				case AI_DOUBLE:
+					Write<double>(&chunk, *((double*) value));
+					break;
+				case AI_AISTRING:
+					Write<aiString>(&chunk, *((aiString*) value));
+					break;
+				case AI_AIVECTOR3D:
+					Write<aiVector3D>(&chunk, *((aiVector3D*) value));
+					break;
+				}
+			}
         }
 
         // -----------------------------------------------------------------------------------

+ 37 - 0
code/AssbinLoader.cpp

@@ -210,6 +210,8 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* p
     (*node)->mTransformation = Read<aiMatrix4x4>(stream);
     (*node)->mNumChildren = Read<unsigned int>(stream);
     (*node)->mNumMeshes = Read<unsigned int>(stream);
+	unsigned int nb_metadata = Read<unsigned int>(stream);
+
     if(parent)
     {
         (*node)->mParent = parent;
@@ -231,6 +233,41 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* p
         }
     }
 
+	if (nb_metadata)
+	{
+		(*node)->mMetaData = aiMetadata::Alloc(nb_metadata);
+		for (unsigned int i = 0; i < nb_metadata; ++i) {
+			(*node)->mMetaData->mKeys[i] = Read<aiString>(stream);
+			(*node)->mMetaData->mValues[i].mType = (aiMetadataType) Read<uint16_t>(stream);
+			void* data = NULL;
+
+			switch ((*node)->mMetaData->mValues[i].mType) {
+			case AI_BOOL:
+				data = new bool(Read<bool>(stream));
+				break;
+			case AI_INT32:
+				data = new int32_t(Read<int32_t>(stream));
+				break;
+			case AI_UINT64:
+				data = new uint64_t(Read<uint64_t>(stream));
+				break;
+			case AI_FLOAT:
+				data = new float(Read<float>(stream));
+				break;
+			case AI_DOUBLE:
+				data = new double(Read<double>(stream));
+				break;
+			case AI_AISTRING:
+				data = new aiString(Read<aiString>(stream));
+				break;
+			case AI_AIVECTOR3D:
+				data = new aiVector3D(Read<aiVector3D>(stream));
+				break;
+			}
+
+			(*node)->mMetaData->mValues[i].mData = data;
+		}
+	}
 }
 
 // -----------------------------------------------------------------------------------

+ 2 - 1
code/AssimpCExport.cpp

@@ -45,8 +45,9 @@ Assimp C export interface. See Exporter.cpp for some notes.
 */
 
 #ifndef ASSIMP_BUILD_NO_EXPORT
+
 #include "CInterfaceIOWrapper.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "ScenePrivate.h"
 #include <assimp/Exporter.hpp>
 

+ 0 - 5
code/BaseImporter.cpp

@@ -337,7 +337,6 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
     if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
         DefaultLogger::get()->debug("Found UTF-32 BOM ...");
 
-        const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
         std::vector<char> output;
         int *ptr = (int*)&data[ 0 ];
         int *end = ptr + ( data.size() / sizeof(int) ) +1;
@@ -358,11 +357,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
     if(*((uint16_t*)&data.front()) == 0xFEFF) {
         DefaultLogger::get()->debug("Found UTF-16 BOM ...");
 
-        const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
         std::vector<unsigned char> output;
-        int16_t *ptr = (int16_t*) &data[ 0 ];
-        int16_t *end = ptr + (data.size() / sizeof(int)) + 1;
-
         utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
         return;
     }

+ 1 - 4
code/BlenderDNA.h

@@ -253,10 +253,7 @@ public:
      *  a compiler complain is the result.
      *  @param dest Destination value to be written
      *  @param db File database, including input stream. */
-    template <typename T> inline void Convert (T& dest,
-        const FileDatabase& db) const;
-
-
+    template <typename T> inline void Convert (T& dest, const FileDatabase& db) const;
 
     // --------------------------------------------------------
     // generic converter

+ 3 - 3
code/BlenderModifier.cpp

@@ -43,10 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of some blender modifiers (i.e subdivision, mirror).
  */
 
-
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
+
 #include "BlenderModifier.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Subdivision.h"
 #include <assimp/scene.h>
 #include <memory>
@@ -266,7 +266,7 @@ void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  co
 
     std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
     std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
-        std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
+        [&out](unsigned int n) { return out.mNumMeshes + n; });
 
     delete[] out.mMeshes;
     out.mMeshes = nind;

+ 6 - 1
code/CMakeLists.txt

@@ -96,6 +96,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/Exporter.hpp
   ${HEADER_PATH}/DefaultIOStream.h
   ${HEADER_PATH}/DefaultIOSystem.h
+  ${HEADER_PATH}/SceneCombiner.h
 )
 
 SET( Core_SRCS
@@ -148,7 +149,6 @@ SET( Common_SRCS
   SpatialSort.cpp
   SpatialSort.h
   SceneCombiner.cpp
-  SceneCombiner.h
   ScenePreprocessor.cpp
   ScenePreprocessor.h
   SkeletonMeshBuilder.cpp
@@ -647,6 +647,9 @@ ADD_ASSIMP_IMPORTER(X3D
   X3DImporter_Rendering.cpp
   X3DImporter_Shape.cpp
   X3DImporter_Texturing.cpp
+  FIReader.hpp
+  FIReader.cpp
+  X3DVocabulary.cpp
 )
 
 ADD_ASSIMP_IMPORTER( GLTF
@@ -732,10 +735,12 @@ SET ( openddl_parser_SRCS
   ../contrib/openddlparser/code/OpenDDLCommon.cpp
   ../contrib/openddlparser/code/OpenDDLExport.cpp
   ../contrib/openddlparser/code/Value.cpp
+  ../contrib/openddlparser/code/OpenDDLStream.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/OpenDDLStream.h
   ../contrib/openddlparser/include/openddlparser/DDLNode.h
   ../contrib/openddlparser/include/openddlparser/Value.h
 )

+ 1 - 1
code/ColladaExporter.cpp

@@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ColladaExporter.h"
 #include "Bitmap.h"
 #include "fast_atof.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "StringUtils.h"
 #include "XMLTools.h"
 #include <assimp/DefaultIOSystem.h>

+ 5 - 7
code/ColladaLoader.cpp

@@ -132,7 +132,6 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // Get file extension list
 const aiImporterDesc* ColladaLoader::GetInfo () const
@@ -1904,14 +1903,13 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
 }
 
 // ------------------------------------------------------------------------------------------------
-// Finds a proper name for a node derived from the collada-node's properties
+// Finds a proper unique name for a node derived from the collada-node's properties.
+// The name must be unique for proper node-bone association.
 std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
 {
-    // now setup the name of the node. We take the name if not empty, otherwise the collada ID
-    // FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default.
-    if (!pNode->mName.empty() && pNode->mName != "untitled")
-        return pNode->mName;
-    else if (!pNode->mID.empty())
+    // Now setup the name of the assimp node. The collada name might not be
+    // unique, so we use the collada ID.
+    if (!pNode->mID.empty())
         return pNode->mID;
     else if (!pNode->mSID.empty())
     return pNode->mSID;

+ 4 - 4
code/ColladaParser.cpp

@@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of the Collada parser helper
  */
 
-
 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
 
 #include <sstream>
@@ -1866,7 +1865,7 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
                 ReadIndexData( pMesh);
             } else
             {
-                // ignore the rest
+                // ignore the restf
                 SkipElement();
             }
         }
@@ -2216,8 +2215,9 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
             else if (IsElement("extra"))
             {
                 SkipElement("extra");
-            } else
-            {
+            } else if ( IsElement("ph")) {                
+                SkipElement("ph");
+            } else {
                 ThrowException( format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">" );
             }
         }

+ 6 - 5
code/Exporter.cpp

@@ -54,7 +54,7 @@ Here we implement only the C++ interface (Assimp::Exporter).
 #ifndef ASSIMP_BUILD_NO_EXPORT
 
 #include "BlobIOSystem.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "BaseProcess.h"
 #include "Importer.h" // need this for GetPostProcessingStepInstanceList()
 
@@ -172,8 +172,10 @@ public:
         GetPostProcessingStepInstanceList(mPostProcessingSteps);
 
         // grab all built-in exporters
-        mExporters.resize(ASSIMP_NUM_EXPORTERS);
-        std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
+        if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) {
+            mExporters.resize( ASSIMP_NUM_EXPORTERS );
+            std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() );
+        }
     }
 
     ~ExporterPimpl()
@@ -187,7 +189,6 @@ public:
     }
 
 public:
-
     aiExportDataBlob* blob;
     std::shared_ptr< Assimp::IOSystem > mIOSystem;
     bool mIsDefaultIOHandler;
@@ -408,6 +409,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
 
     pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
+    
     return AI_FAILURE;
 }
 
@@ -492,7 +494,6 @@ ExportProperties::ExportProperties(const ExportProperties &other)
     // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) {

+ 3 - 4
code/FBXBinaryTokenizer.cpp

@@ -161,8 +161,7 @@ uint32_t ReadWord(const char* input, const char*& cursor, const char* end)
 }
 
 // ------------------------------------------------------------------------------------------------
-uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end)
-{
+uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) {
     const size_t k_to_read = sizeof(uint64_t);
     if(Offset(cursor, end) < k_to_read) {
         TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
@@ -176,7 +175,6 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end)
     return dword;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 uint8_t ReadByte(const char* input, const char*& cursor, const char* end)
 {
@@ -447,8 +445,9 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le
     const uint32_t flags = ReadWord(input, cursor, input + length);
 
     const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
+    (void) padding_0;
     const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused
-
+    (void) padding_1;
     while (cursor < input + length)
     {
         if(!ReadScope(output_tokens, input, cursor, input + length, flags)) {

+ 40 - 17
code/FBXConverter.cpp

@@ -436,6 +436,19 @@ private:
 
     aiScene* const out;
     const FBX::Document& doc;
+
+	bool FindTextureIndexByFilename(const Video& video, unsigned int& index) {
+		index = 0;
+		const char* videoFileName = video.FileName().c_str();
+		for (auto texture = textures_converted.begin(); texture != textures_converted.end(); ++texture)
+		{
+			if (!strcmp(texture->first->FileName().c_str(), videoFileName)) {
+				return true;
+			}
+			index++;
+		}
+		return false;
+	}
 };
 
 Converter::Converter( aiScene* out, const Document& doc )
@@ -1749,7 +1762,7 @@ unsigned int Converter::ConvertVideo( const Video& video )
     out_tex->mWidth = static_cast<unsigned int>( video.ContentLength() ); // total data size
     out_tex->mHeight = 0; // fixed to 0
 
-                            // steal the data from the Video to avoid an additional copy
+    // steal the data from the Video to avoid an additional copy
     out_tex->pcData = reinterpret_cast<aiTexel*>( const_cast<Video&>( video ).RelinquishContent() );
 
     // try to extract a hint from the file extension
@@ -1783,22 +1796,32 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
         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 );
-        }
+        if (media != 0) {
+			bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
+			unsigned int index;
+
+			VideoMap::const_iterator it = textures_converted.find(media);
+			if (it != textures_converted.end()) {
+				index = (*it).second;
+				textureReady = true;
+			}
+			else {
+				if (media->ContentLength() > 0) {
+					index = ConvertVideo(*media);
+					textures_converted[media] = index;
+					textureReady = true;
+				}
+				else if (doc.Settings().searchEmbeddedTextures) { //try to find the texture on the already-loaded textures by the filename, if the flag is on					
+					textureReady = FindTextureIndexByFilename(*media, index);
+				}
+			}
+
+			// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
+			if (textureReady) {
+				path.data[0] = '*';
+				path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+			}
+		}  
 
         out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 );
 

+ 2 - 2
code/FBXDocument.cpp

@@ -565,7 +565,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id,
         temp.push_back((*it).second);
     }
 
-    std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
+    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
 
     return temp; // NRVO should handle this
 }
@@ -617,7 +617,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
         temp.push_back((*it).second);
     }
 
-    std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
+    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
     return temp; // NRVO should handle this
 }
 

+ 5 - 0
code/FBXImportSettings.h

@@ -63,6 +63,7 @@ struct ImportSettings
         , readWeights(true)
         , preservePivots(true)
         , optimizeEmptyAnimationCurves(true)
+		, searchEmbeddedTextures(false)
     {}
 
 
@@ -137,6 +138,10 @@ struct ImportSettings
      *  values matching the corresponding node transformation.
      *  The default value is true. */
     bool optimizeEmptyAnimationCurves;
+
+	/** search for embedded loaded textures, where no embedded texture data is provided.
+	*  The default value is false. */
+	bool searchEmbeddedTextures;
 };
 
 

+ 1 - 0
code/FBXImporter.cpp

@@ -131,6 +131,7 @@ void FBXImporter::SetupProperties(const Importer* pImp)
     settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
     settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
     settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
+	settings.searchEmbeddedTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES, false);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 29 - 24
code/FBXMaterial.cpp

@@ -281,7 +281,7 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
     const Scope& sc = GetRequiredScope(element);
 
     const Element* const Type = sc["Type"];
-    const Element* const FileName = sc["FileName"];
+    const Element* const FileName = sc.FindElementCaseInsensitive("FileName");  //some files retain the information as "Filename", others "FileName", who knows
     const Element* const RelativeFilename = sc["RelativeFilename"];
     const Element* const Content = sc["Content"];
 
@@ -291,35 +291,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
 
     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<size_t>(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);
-        }
+		//this field is ommited when the embedded texture is already loaded, let's ignore if it´s not found
+		try {
+			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<size_t>(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);
+			}
+		} catch (runtime_error runtimeError) {
+			//we don´t need the content data for contents that has already been loaded
+		}
     }
 
     props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);

+ 1 - 1
code/FBXMeshGeometry.cpp

@@ -357,7 +357,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
         // avoids losing the material if there are more material layers
         // coming of which at least one contains actual data (did observe
         // that with one test file).
-        const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
+        const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
         if(count_neg == temp_materials.size()) {
             FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
             return;

+ 12 - 0
code/FBXParser.h

@@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <memory>
 #include "LogAux.h"
+#include "fast_atof.h"
 
 #include "FBXCompileConfig.h"
 #include "FBXTokenizer.h"
@@ -137,6 +138,17 @@ public:
         return it == elements.end() ? NULL : (*it).second;
     }
 
+	const Element* FindElementCaseInsensitive(const std::string& elementName) const {
+		const char* elementNameCStr = elementName.c_str();
+		for (auto element = elements.begin(); element != elements.end(); ++element)
+		{
+			if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) {
+				return element->second;
+			}
+		}
+		return NULL;
+	}
+
     ElementCollection GetCollection(const std::string& index) const {
         return elements.equal_range(index);
     }

+ 1818 - 0
code/FIReader.cpp

@@ -0,0 +1,1818 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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   FIReader.cpp
+/// \brief  Reader for Fast Infoset encoded binary XML files.
+/// \date   2017
+/// \author Patrick Daehne
+
+#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
+#include "FIReader.hpp"
+#include "Exceptional.h"
+#include <assimp/IOStream.hpp>
+#include <assimp/types.h>
+#include "MemoryIOWrapper.h"
+#include "irrXMLWrapper.h"
+#include "../contrib/utf8cpp/source/utf8.h"
+#include <stack>
+#include <map>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+namespace Assimp {
+
+static const std::string parseErrorMessage = "Fast Infoset parse error";
+
+static const char *xmlDeclarations[] = {
+    "<?xml encoding='finf'?>",
+    "<?xml encoding='finf' standalone='yes'?>",
+    "<?xml encoding='finf' standalone='no'?>",
+    "<?xml version='1.0' encoding='finf'?>",
+    "<?xml version='1.0' encoding='finf' standalone='yes'?>",
+    "<?xml version='1.0' encoding='finf' standalone='no'?>",
+    "<?xml version='1.1' encoding='finf'?>",
+    "<?xml version='1.1' encoding='finf' standalone='yes'?>",
+    "<?xml version='1.1' encoding='finf' standalone='no'?>"
+};
+
+static size_t parseMagic(const uint8_t *data, const uint8_t *dataEnd) {
+    if (dataEnd - data < 4) {
+        return 0;
+    }
+    uint32_t magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+    switch (magic) {
+    case 0xe0000001:
+        return 4;
+    case 0x3c3f786d: // "<?xm"
+        {
+            size_t xmlDeclarationsLength = sizeof(xmlDeclarations) / sizeof(xmlDeclarations[0]);
+            for (size_t i = 0; i < xmlDeclarationsLength; ++i) {
+                auto xmlDeclaration = xmlDeclarations[i];
+                ptrdiff_t xmlDeclarationLength = strlen(xmlDeclaration);
+                if ((dataEnd - data >= xmlDeclarationLength) && (memcmp(xmlDeclaration, data, xmlDeclarationLength) == 0)) {
+                    data += xmlDeclarationLength;
+                    if (dataEnd - data < 4) {
+                        return 0;
+                    }
+                    magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+                    return magic == 0xe0000001 ? xmlDeclarationLength + 4 : 0;
+                }
+            }
+            return 0;
+        }
+    default:
+        return 0;
+    }
+}
+
+static std::string parseUTF8String(const uint8_t *data, size_t len) {
+    return std::string((char*)data, len);
+}
+
+static std::string parseUTF16String(const uint8_t *data, size_t len) {
+    if (len & 1) {
+        throw DeadlyImportError(parseErrorMessage);
+    }
+    size_t numShorts = len / 2;
+    std::vector<short> utf16;
+    utf16.reserve(numShorts);
+    for (size_t i = 0; i < numShorts; ++i) {
+        short v = (data[0] << 8) | data[1];
+        utf16.push_back(v);
+        data += 2;
+    }
+    std::string result;
+    utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(result));
+    return result;
+}
+
+struct FIStringValueImpl: public FIStringValue {
+    inline FIStringValueImpl(std::string &&value_) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ { return value; }
+};
+
+std::shared_ptr<FIStringValue> FIStringValue::create(std::string &&value) {
+    return std::make_shared<FIStringValueImpl>(std::move(value));
+}
+
+struct FIHexValueImpl: public FIHexValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIHexValueImpl(std::vector<uint8_t> &&value_):  strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            os << std::hex << std::uppercase << std::setfill('0');
+            std::for_each(value.begin(), value.end(), [&](uint8_t c) { os << std::setw(2) << static_cast<int>(c); });
+            strValue = os.str();
+        }
+        return strValue;
+    };
+};
+
+std::shared_ptr<FIHexValue> FIHexValue::create(std::vector<uint8_t> &&value) {
+    return std::make_shared<FIHexValueImpl>(std::move(value));
+}
+
+struct FIBase64ValueImpl: public FIBase64Value {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIBase64ValueImpl(std::vector<uint8_t> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            uint8_t c1, c2;
+            int imod3 = 0;
+            std::vector<uint8_t>::size_type valueSize = value.size();
+            for (std::vector<uint8_t>::size_type i = 0; i < valueSize; ++i) {
+                c2 = value[i];
+                switch (imod3) {
+                case 0:
+                    os << basis_64[c2 >> 2];
+                    imod3 = 1;
+                    break;
+                case 1:
+                    os << basis_64[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)];
+                    imod3 = 2;
+                    break;
+                case 2:
+                    os << basis_64[((c1 & 0x0f) << 2) | ((c2 & 0xc0) >> 6)] << basis_64[c2 & 0x3f];
+                    imod3 = 0;
+                    break;
+                }
+                c1 = c2;
+            }
+            switch (imod3) {
+            case 1:
+                os << basis_64[(c1 & 0x03) << 4] << "==";
+                break;
+            case 2:
+                os << basis_64[(c1 & 0x0f) << 2] << '=';
+                break;
+            }
+            strValue = os.str();
+        }
+        return strValue;
+    };
+    static const char basis_64[];
+};
+
+const char FIBase64ValueImpl::basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+std::shared_ptr<FIBase64Value> FIBase64Value::create(std::vector<uint8_t> &&value) {
+    return std::make_shared<FIBase64ValueImpl>(std::move(value));
+}
+
+struct FIShortValueImpl: public FIShortValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIShortValueImpl(std::vector<int16_t> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](int16_t s) { if (++n > 1) os << ' '; os << s; });
+            strValue = os.str();
+        }
+        return strValue;
+    }
+};
+
+std::shared_ptr<FIShortValue> FIShortValue::create(std::vector<int16_t> &&value) {
+    return std::make_shared<FIShortValueImpl>(std::move(value));
+}
+
+struct FIIntValueImpl: public FIIntValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIIntValueImpl(std::vector<int32_t> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](int32_t i) { if (++n > 1) os << ' '; os << i; });
+            strValue = os.str();
+        }
+        return strValue;
+    };
+};
+
+std::shared_ptr<FIIntValue> FIIntValue::create(std::vector<int32_t> &&value) {
+    return std::make_shared<FIIntValueImpl>(std::move(value));
+}
+
+struct FILongValueImpl: public FILongValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FILongValueImpl(std::vector<int64_t> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](int64_t l) { if (++n > 1) os << ' '; os << l; });
+            strValue = os.str();
+        }
+        return strValue;
+    };
+};
+
+std::shared_ptr<FILongValue> FILongValue::create(std::vector<int64_t> &&value) {
+    return std::make_shared<FILongValueImpl>(std::move(value));
+}
+
+struct FIBoolValueImpl: public FIBoolValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIBoolValueImpl(std::vector<bool> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            os << std::boolalpha;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](bool b) { if (++n > 1) os << ' '; os << b; });
+            strValue = os.str();
+        }
+        return strValue;
+    };
+};
+
+std::shared_ptr<FIBoolValue> FIBoolValue::create(std::vector<bool> &&value) {
+    return std::make_shared<FIBoolValueImpl>(std::move(value));
+}
+
+struct FIFloatValueImpl: public FIFloatValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIFloatValueImpl(std::vector<float> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](float f) { if (++n > 1) os << ' '; os << f; });
+            strValue = os.str();
+        }
+        return strValue;
+    }
+};
+
+std::shared_ptr<FIFloatValue> FIFloatValue::create(std::vector<float> &&value) {
+    return std::make_shared<FIFloatValueImpl>(std::move(value));
+}
+
+struct FIDoubleValueImpl: public FIDoubleValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIDoubleValueImpl(std::vector<double> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            int n = 0;
+            std::for_each(value.begin(), value.end(), [&](double d) { if (++n > 1) os << ' '; os << d; });
+            strValue = os.str();
+        }
+        return strValue;
+    }
+};
+
+std::shared_ptr<FIDoubleValue> FIDoubleValue::create(std::vector<double> &&value) {
+    return std::make_shared<FIDoubleValueImpl>(std::move(value));
+}
+
+struct FIUUIDValueImpl: public FIUUIDValue {
+    mutable std::string strValue;
+    mutable bool strValueValid;
+    inline FIUUIDValueImpl(std::vector<uint8_t> &&value_): strValueValid(false) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ {
+        if (!strValueValid) {
+            strValueValid = true;
+            std::ostringstream os;
+            os << std::hex << std::uppercase << std::setfill('0');
+            std::vector<uint8_t>::size_type valueSize = value.size();
+            for (std::vector<uint8_t>::size_type i = 0; i < valueSize; ++i) {
+                switch (i & 15) {
+                case 0:
+                    if (i > 0) {
+                        os << ' ';
+                    }
+                    os << std::setw(2) << static_cast<int>(value[i]);
+                    break;
+                case 4:
+                case 6:
+                case 8:
+                case 10:
+                    os << '-';
+                    // intentionally fall through!
+                case 1:
+                case 2:
+                case 3:
+                case 5:
+                case 7:
+                case 9:
+                case 11:
+                case 12:
+                case 13:
+                case 14:
+                case 15:
+                    os << std::setw(2) << static_cast<int>(value[i]);
+                    break;
+                }
+            }
+            strValue = os.str();
+        }
+        return strValue;
+    };
+};
+
+std::shared_ptr<FIUUIDValue> FIUUIDValue::create(std::vector<uint8_t> &&value) {
+    return std::make_shared<FIUUIDValueImpl>(std::move(value));
+}
+
+struct FICDATAValueImpl: public FICDATAValue {
+    inline FICDATAValueImpl(std::string &&value_) { value = std::move(value_); }
+    virtual const std::string &toString() const /*override*/ { return value; }
+};
+
+std::shared_ptr<FICDATAValue> FICDATAValue::create(std::string &&value) {
+    return std::make_shared<FICDATAValueImpl>(std::move(value));
+}
+
+struct FIHexDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        return FIHexValue::create(std::vector<uint8_t>(data, data + len));
+    }
+};
+
+struct FIBase64Decoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        return FIBase64Value::create(std::vector<uint8_t>(data, data + len));
+    }
+};
+
+struct FIShortDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 1) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<int16_t> value;
+        size_t numShorts = len / 2;
+        value.reserve(numShorts);
+        for (size_t i = 0; i < numShorts; ++i) {
+            int16_t v = (data[0] << 8) | data[1];
+            value.push_back(v);
+            data += 2;
+        }
+        return FIShortValue::create(std::move(value));
+    }
+};
+
+struct FIIntDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 3) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<int32_t> value;
+        size_t numInts = len / 4;
+        value.reserve(numInts);
+        for (size_t i = 0; i < numInts; ++i) {
+            int32_t v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+            value.push_back(v);
+            data += 4;
+        }
+        return FIIntValue::create(std::move(value));
+    }
+};
+
+struct FILongDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 7) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<int64_t> value;
+        size_t numLongs = len / 8;
+        value.reserve(numLongs);
+        for (size_t i = 0; i < numLongs; ++i) {
+            int64_t b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
+            int64_t v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
+            value.push_back(v);
+            data += 8;
+        }
+        return FILongValue::create(std::move(value));
+    }
+};
+
+struct FIBoolDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len < 1) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<bool> value;
+        uint8_t b = *data++;
+        size_t unusedBits = b >> 4;
+        size_t numBools = (len * 8) - 4 - unusedBits;
+        value.reserve(numBools);
+        uint8_t mask = 1 << 3;
+        for (size_t i = 0; i < numBools; ++i) {
+            if (!mask) {
+                mask = 1 << 7;
+                b = *data++;
+            }
+            value.push_back((b & mask) != 0);
+        }
+        return FIBoolValue::create(std::move(value));
+    }
+};
+
+struct FIFloatDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 3) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<float> value;
+        size_t numFloats = len / 4;
+        value.reserve(numFloats);
+        for (size_t i = 0; i < numFloats; ++i) {
+            int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+            value.push_back(*(float*)&v);
+            data += 4;
+        }
+        return FIFloatValue::create(std::move(value));
+    }
+};
+
+struct FIDoubleDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 7) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::vector<double> value;
+        size_t numDoubles = len / 8;
+        value.reserve(numDoubles);
+        for (size_t i = 0; i < numDoubles; ++i) {
+            long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
+            long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
+            value.push_back(*(double*)&v);
+            data += 8;
+        }
+        return FIDoubleValue::create(std::move(value));
+    }
+};
+
+struct FIUUIDDecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        if (len & 15) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        return FIUUIDValue::create(std::vector<uint8_t>(data, data + len));
+    }
+};
+
+struct FICDATADecoder: public FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
+        return FICDATAValue::create(parseUTF8String(data, len));
+    }
+};
+
+class CFIReaderImpl: public FIReader {
+public:
+
+    CFIReaderImpl(std::unique_ptr<uint8_t[]> data_, size_t size):
+    data(std::move(data_)), dataP(data.get()), dataEnd(data.get() + size), currentNodeType(irr::io::EXN_NONE),
+    emptyElement(false), headerPending(true), terminatorPending(false)
+    {}
+
+    virtual ~CFIReaderImpl() {}
+
+    virtual bool read() /*override*/ {
+        if (headerPending) {
+            headerPending = false;
+            parseHeader();
+        }
+        if (terminatorPending) {
+            terminatorPending = false;
+            if (elementStack.empty()) {
+                return false;
+            }
+            else {
+                nodeName = elementStack.top();
+                elementStack.pop();
+                currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END;
+                return true;
+            }
+        }
+        if (dataP >= dataEnd) {
+            return false;
+        }
+        uint8_t b = *dataP;
+        if (b < 0x80) { // Element (C.2.11.2, C.3.7.2)
+            // C.3
+            parseElement();
+            return true;
+        }
+        else if (b < 0xc0) { // Characters (C.3.7.5)
+            // C.7
+            auto chars = parseNonIdentifyingStringOrIndex3(vocabulary.charactersTable);
+            nodeName = chars->toString();
+            currentNodeType = irr::io::EXN_TEXT;
+            return true;
+        }
+        else if (b < 0xe0) {
+            if ((b & 0xfc) == 0xc4) { // DTD (C.2.11.5)
+                // C.9
+                ++dataP;
+                if (b & 0x02) {
+                    /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                if (b & 0x01) {
+                    /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                elementStack.push(EmptyString);
+                currentNodeType = irr::io::EXN_UNKNOWN;
+                return true;
+            }
+            else if ((b & 0xfc) == 0xc8) { // Unexpanded entity reference (C.3.7.4)
+                // C.6
+                ++dataP;
+                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
+                if (b & 0x02) {
+                    /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                if (b & 0x01) {
+                    /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                currentNodeType = irr::io::EXN_UNKNOWN;
+                return true;
+            }
+        }
+        else if (b < 0xf0) {
+            if (b == 0xe1) { // Processing instruction (C.2.11.3, C.3.7.3)
+                // C.5
+                ++dataP;
+                /*const std::string &target =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                /*std::shared_ptr<const FIValue> data =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
+                currentNodeType = irr::io::EXN_UNKNOWN;
+                return true;
+            }
+            else if (b == 0xe2) { // Comment (C.2.11.4, C.3.7.6)
+                // C.8
+                ++dataP;
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                std::shared_ptr<const FIValue> comment = parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
+                nodeName = comment->toString();
+                currentNodeType = irr::io::EXN_COMMENT;
+                return true;
+            }
+        }
+        else { // Terminator (C.2.12, C.3.8)
+            ++dataP;
+            if (b == 0xff) {
+                terminatorPending = true;
+            }
+            if (elementStack.empty()) {
+                return false;
+            }
+            else {
+                nodeName = elementStack.top();
+                elementStack.pop();
+                currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END;
+                return true;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    virtual irr::io::EXML_NODE getNodeType() const /*override*/ {
+        return currentNodeType;
+    }
+
+    virtual int getAttributeCount() const /*override*/ {
+        return static_cast<int>(attributes.size());
+    }
+
+    virtual const char* getAttributeName(int idx) const /*override*/ {
+        if (idx < 0 || idx >= (int)attributes.size()) {
+            return nullptr;
+        }
+        return attributes[idx].name.c_str();
+    }
+
+    virtual const char* getAttributeValue(int idx) const /*override*/ {
+        if (idx < 0 || idx >= (int)attributes.size()) {
+            return nullptr;
+        }
+        return attributes[idx].value->toString().c_str();
+    }
+
+    virtual const char* getAttributeValue(const char* name) const /*override*/ {
+        const Attribute* attr = getAttributeByName(name);
+        if (!attr) {
+            return nullptr;
+        }
+        return attr->value->toString().c_str();
+    }
+
+    virtual const char* getAttributeValueSafe(const char* name) const /*override*/ {
+        const Attribute* attr = getAttributeByName(name);
+        if (!attr) {
+            return EmptyString.c_str();
+        }
+        return attr->value->toString().c_str();
+    }
+
+    virtual int getAttributeValueAsInt(const char* name) const /*override*/ {
+        const Attribute* attr = getAttributeByName(name);
+        if (!attr) {
+            return 0;
+        }
+        std::shared_ptr<const FIIntValue> intValue = std::dynamic_pointer_cast<const FIIntValue>(attr->value);
+        if (intValue) {
+            return intValue->value.size() == 1 ? intValue->value.front() : 0;
+        }
+        return stoi(attr->value->toString());
+    }
+
+    virtual int getAttributeValueAsInt(int idx) const /*override*/ {
+        if (idx < 0 || idx >= (int)attributes.size()) {
+            return 0;
+        }
+        std::shared_ptr<const FIIntValue> intValue = std::dynamic_pointer_cast<const FIIntValue>(attributes[idx].value);
+        if (intValue) {
+            return intValue->value.size() == 1 ? intValue->value.front() : 0;
+        }
+        return stoi(attributes[idx].value->toString());
+    }
+
+    virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
+        const Attribute* attr = getAttributeByName(name);
+        if (!attr) {
+            return 0;
+        }
+        std::shared_ptr<const FIFloatValue> floatValue = std::dynamic_pointer_cast<const FIFloatValue>(attr->value);
+        if (floatValue) {
+            return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
+        }
+        return stof(attr->value->toString());
+    }
+
+    virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
+        if (idx < 0 || idx >= (int)attributes.size()) {
+            return 0;
+        }
+        std::shared_ptr<const FIFloatValue> floatValue = std::dynamic_pointer_cast<const FIFloatValue>(attributes[idx].value);
+        if (floatValue) {
+            return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
+        }
+        return stof(attributes[idx].value->toString());
+    }
+
+    virtual const char* getNodeName() const /*override*/ {
+        return nodeName.c_str();
+    }
+
+    virtual const char* getNodeData() const /*override*/ {
+        return nodeName.c_str();
+    }
+
+    virtual bool isEmptyElement() const /*override*/ {
+        return emptyElement;
+    }
+
+    virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ {
+        return irr::io::ETF_UTF8;
+    }
+
+    virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ {
+        return irr::io::ETF_UTF8;
+    }
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const /*override*/ {
+        if (idx < 0 || idx >= (int)attributes.size()) {
+            return nullptr;
+        }
+        return attributes[idx].value;
+    }
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* name) const /*override*/ {
+        const Attribute* attr = getAttributeByName(name);
+        if (!attr) {
+            return nullptr;
+        }
+        return attr->value;
+    }
+
+    virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) /*override*/ {
+        decoderMap[algorithmUri] = std::move(decoder);
+    }
+
+    virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ {
+        vocabularyMap[vocabularyUri] = vocabulary;
+    }
+
+private:
+
+    struct QName {
+        std::string prefix;
+        std::string uri;
+        std::string name;
+        inline QName() {}
+        inline QName(const FIQName &qname): prefix(qname.prefix ? qname.prefix : ""), uri(qname.uri ? qname.uri : ""), name(qname.name) {}
+    };
+
+    struct Attribute {
+        QName qname;
+        std::string name;
+        std::shared_ptr<const FIValue> value;
+    };
+
+    struct Vocabulary {
+        std::vector<std::string> restrictedAlphabetTable;
+        std::vector<std::string> encodingAlgorithmTable;
+        std::vector<std::string> prefixTable;
+        std::vector<std::string> namespaceNameTable;
+        std::vector<std::string> localNameTable;
+        std::vector<std::string> otherNCNameTable;
+        std::vector<std::string> otherURITable;
+        std::vector<std::shared_ptr<const FIValue>> attributeValueTable;
+        std::vector<std::shared_ptr<const FIValue>> charactersTable;
+        std::vector<std::shared_ptr<const FIValue>> otherStringTable;
+        std::vector<QName> elementNameTable;
+        std::vector<QName> attributeNameTable;
+        Vocabulary() {
+            prefixTable.push_back("xml");
+            namespaceNameTable.push_back("http://www.w3.org/XML/1998/namespace");
+        }
+    };
+
+    const Attribute* getAttributeByName(const char* name) const {
+        if (!name) {
+            return 0;
+        }
+        std::string n = name;
+        for (int i=0; i<(int)attributes.size(); ++i) {
+            if (attributes[i].name == n) {
+                return &attributes[i];
+            }
+        }
+        return 0;
+    }
+
+    size_t parseInt2() { // C.25
+        uint8_t b = *dataP++;
+        if (!(b & 0x40)) { // x0...... (C.25.2)
+            return b & 0x3f;
+        }
+        else if ((b & 0x60) == 0x40) { // x10..... ........ (C.25.3)
+            if (dataEnd - dataP > 0) {
+                return (((b & 0x1f) << 8) | *dataP++) + 0x40;
+            }
+        }
+        else if ((b & 0x70) == 0x60) { // x110.... ........ ........ (C.25.4)
+            if (dataEnd - dataP > 1) {
+                size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x2040;
+                dataP += 2;
+                return result;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    size_t parseInt3() { // C.27
+        uint8_t b = *dataP++;
+        if (!(b & 0x20)) { // xx0..... (C.27.2)
+            return b & 0x1f;
+        }
+        else if ((b & 0x38) == 0x20) { // xx100... ........ (C.27.3)
+            if (dataEnd - dataP > 0) {
+                return (((b & 0x07) << 8) | *dataP++) + 0x20;
+            }
+        }
+        else if ((b & 0x38) == 0x28) { // xx101... ........ ........ (C.27.4)
+            if (dataEnd - dataP > 1) {
+                size_t result = (((b & 0x07) << 16) | (dataP[0] << 8) | dataP[1]) + 0x820;
+                dataP += 2;
+                return result;
+            }
+        }
+        else if ((b & 0x3f) == 0x30) { // xx110000 0000.... ........ ........ (C.27.5)
+            if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) {
+                size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x80820;
+                dataP += 3;
+                return result;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    size_t parseInt4() { // C.28
+        uint8_t b = *dataP++;
+        if (!(b & 0x10)) { // xxx0.... (C.28.2)
+            return b & 0x0f;
+        }
+        else if ((b & 0x1c) == 0x10) { // xxx100.. ........ (C.28.3)
+            if (dataEnd - dataP > 0) {
+                return (((b & 0x03) << 8) | *dataP++) + 0x10;
+            }
+        }
+        else if ((b & 0x1c) == 0x14) { // xxx101.. ........ ........ (C.28.4)
+            if (dataEnd - dataP > 1) {
+                size_t result = (((b & 0x03) << 16) | (dataP[0] << 8) | dataP[1]) + 0x410;
+                dataP += 2;
+                return result;
+            }
+        }
+        else if ((b & 0x1f) == 0x18) { // xxx11000 0000.... ........ ........ (C.28.5)
+            if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) {
+                size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x40410;
+                dataP += 3;
+                return result;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    size_t parseSequenceLen() { // C.21
+        if (dataEnd - dataP > 0) {
+            uint8_t b = *dataP++;
+            if (b < 0x80) { // 0....... (C.21.2)
+                return b;
+            }
+            else if ((b & 0xf0) == 0x80) { // 1000.... ........ ........ (C.21.3)
+                if (dataEnd - dataP > 1) {
+                    size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x80;
+                    dataP += 2;
+                    return result;
+                }
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    std::string parseNonEmptyOctetString2() { // C.22
+        // Parse the length of the string
+        uint8_t b = *dataP++ & 0x7f;
+        size_t len;
+        if (!(b & 0x40)) { // x0...... (C.22.3.1)
+            len = b + 1;
+        }
+        else if (b == 0x40) { // x1000000 ........ (C.22.3.2)
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            len = *dataP++ + 0x41;
+        }
+        else if (b == 0x60) { // x1100000 ........ ........ ........ ........ (C.22.3.3)
+            if (dataEnd - dataP < 4) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            len = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x141;
+            dataP += 4;
+        }
+        else {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+
+        // Parse the string (C.22.4)
+        if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        std::string s = parseUTF8String(dataP, len);
+        dataP += len;
+
+        return s;
+    }
+
+    size_t parseNonEmptyOctetString5Length() { // C.23
+        // Parse the length of the string
+        size_t b = *dataP++ & 0x0f;
+        if (!(b & 0x08)) { // xxxx0... (C.23.3.1)
+            return b + 1;
+        }
+        else if (b == 0x08) { // xxxx1000 ........ (C.23.3.2)
+            if (dataEnd - dataP > 0) {
+                return *dataP++ + 0x09;
+            }
+        }
+        else if (b == 0x0c) { // xxxx1100 ........ ........ ........ ........ (C.23.3.3)
+            if (dataEnd - dataP > 3) {
+                size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x109;
+                dataP += 4;
+                return result;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    size_t parseNonEmptyOctetString7Length() { // C.24
+        // Parse the length of the string
+        size_t b = *dataP++ & 0x03;
+        if (!(b & 0x02)) { // xxxxxx0. (C.24.3.1)
+            return b + 1;
+        }
+        else if (b == 0x02) { // xxxxxx10 ........ (C.24.3.2)
+            if (dataEnd - dataP > 0) {
+                return *dataP++ + 0x3;
+            }
+        }
+        else if (b == 0x03) { // xxxxxx11 ........ ........ ........ ........ (C.24.3.3)
+            if (dataEnd - dataP > 3) {
+                size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x103;
+                dataP += 4;
+                return result;
+            }
+        }
+        throw DeadlyImportError(parseErrorMessage);
+    }
+
+    std::shared_ptr<const FIValue> parseEncodedData(size_t index, size_t len) {
+        if (index < 32) {
+            FIDecoder *decoder = defaultDecoder[index];
+            if (!decoder) {
+                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+            }
+            return decoder->decode(dataP, len);
+        }
+        else {
+            if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) {
+                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+            }
+            std::string uri = vocabulary.encodingAlgorithmTable[index - 32];
+            auto it = decoderMap.find(uri);
+            if (it == decoderMap.end()) {
+                throw DeadlyImportError("Unsupported encoding algorithm " + uri);
+            }
+            else {
+                return it->second->decode(dataP, len);
+            }
+        }
+    }
+
+    std::shared_ptr<const FIValue> parseRestrictedAlphabet(size_t index, size_t len) {
+        std::string alphabet;
+        if (index < 16) {
+            switch (index) {
+            case 0: // numeric
+                alphabet = "0123456789-+.e ";
+                break;
+            case 1: // date and time
+                alphabet = "0123456789-:TZ ";
+                break;
+            default:
+                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+            }
+        }
+        else {
+            if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) {
+                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+            }
+            alphabet = vocabulary.restrictedAlphabetTable[index - 16];
+        }
+        std::vector<uint32_t> alphabetUTF32;
+        utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32));
+        std::string::size_type alphabetLength = alphabetUTF32.size();
+        if (alphabetLength < 2) {
+            throw DeadlyImportError("Invalid restricted alphabet length " + std::to_string(alphabetLength));
+        }
+        std::string::size_type bitsPerCharacter = 1;
+        while ((1ull << bitsPerCharacter) <= alphabetLength) {
+            ++bitsPerCharacter;
+        }
+        size_t bitsAvail = 0;
+        uint8_t mask = (1 << bitsPerCharacter) - 1;
+        uint32_t bits = 0;
+        std::string s;
+        for (size_t i = 0; i < len; ++i) {
+            bits = (bits << 8) | dataP[i];
+            bitsAvail += 8;
+            while (bitsAvail >= bitsPerCharacter) {
+                bitsAvail -= bitsPerCharacter;
+                size_t charIndex = (bits >> bitsAvail) & mask;
+                if (charIndex < alphabetLength) {
+                    s.push_back(alphabetUTF32[charIndex]);
+                }
+                else if (charIndex != mask) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+            }
+        }
+        return FIStringValue::create(std::move(s));
+    }
+
+    std::shared_ptr<const FIValue> parseEncodedCharacterString3() { // C.19
+        std::shared_ptr<const FIValue> result;
+        size_t len;
+        uint8_t b = *dataP;
+        if (b & 0x20) {
+            ++dataP;
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            size_t index = ((b & 0x0f) << 4) | ((*dataP & 0xf0) >> 4); // C.29
+            len = parseNonEmptyOctetString5Length();
+            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            if (b & 0x10) {
+                // encoding algorithm (C.19.3.4)
+                result = parseEncodedData(index, len);
+            }
+            else {
+                // Restricted alphabet (C.19.3.3)
+                result = parseRestrictedAlphabet(index, len);
+            }
+        }
+        else {
+            len = parseNonEmptyOctetString5Length();
+            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            if (b & 0x10) {
+                // UTF-16 (C.19.3.2)
+                if (len & 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                result = FIStringValue::create(parseUTF16String(dataP, len));
+            }
+            else {
+                // UTF-8 (C.19.3.1)
+                result = FIStringValue::create(parseUTF8String(dataP, len));
+            }
+        }
+        dataP += len;
+        return result;
+    }
+
+    std::shared_ptr<const FIValue> parseEncodedCharacterString5() { // C.20
+        std::shared_ptr<const FIValue> result;
+        size_t len;
+        uint8_t b = *dataP;
+        if (b & 0x08) {
+            ++dataP;
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            size_t index = ((b & 0x03) << 6) | ((*dataP & 0xfc) >> 2); /* C.29 */
+            len = parseNonEmptyOctetString7Length();
+            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            if (b & 0x04) {
+                // encoding algorithm (C.20.3.4)
+                result = parseEncodedData(index, len);
+            }
+            else {
+                // Restricted alphabet (C.20.3.3)
+                result = parseRestrictedAlphabet(index, len);
+            }
+        }
+        else {
+            len = parseNonEmptyOctetString7Length();
+            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            if (b & 0x04) {
+                // UTF-16 (C.20.3.2)
+                if (len & 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                result = FIStringValue::create(parseUTF16String(dataP, len));
+            }
+            else {
+                // UTF-8 (C.20.3.1)
+                result = FIStringValue::create(parseUTF8String(dataP, len));
+            }
+        }
+        dataP += len;
+        return result;
+    }
+
+    const std::string &parseIdentifyingStringOrIndex(std::vector<std::string> &stringTable) { // C.13
+        if (dataEnd - dataP < 1) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        uint8_t b = *dataP;
+        if (b & 0x80) {
+            // We have an index (C.13.4)
+            size_t index = parseInt2();
+            if (index >= stringTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            return stringTable[index];
+        }
+        else {
+            // We have a string (C.13.3)
+            stringTable.push_back(parseNonEmptyOctetString2());
+            return stringTable.back();
+        }
+    }
+
+    QName parseNameSurrogate() { // C.16
+        if (dataEnd - dataP < 1) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        uint8_t b = *dataP++;
+        if (b & 0xfc) { // Padding '000000' C.2.5.5
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        QName result;
+        size_t index;
+        if (b & 0x02) { // prefix (C.16.3)
+            if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            index = parseInt2();
+            if (index >= vocabulary.prefixTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            result.prefix = vocabulary.prefixTable[index];
+        }
+        if (b & 0x01) { // namespace-name (C.16.4)
+            if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            index = parseInt2();
+            if (index >= vocabulary.namespaceNameTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            result.uri = vocabulary.namespaceNameTable[index];
+        }
+        // local-name
+        if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        index = parseInt2();
+        if (index >= vocabulary.localNameTable.size()) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        result.name = vocabulary.localNameTable[index];
+        return result;
+    }
+
+    const QName &parseQualifiedNameOrIndex2(std::vector<QName> &qNameTable) { // C.17
+        uint8_t b = *dataP;
+        if ((b & 0x7c) == 0x78) { // x11110..
+            // We have a literal (C.17.3)
+            ++dataP;
+            QName result;
+            // prefix (C.17.3.1)
+            result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
+            // namespace-name (C.17.3.1)
+            result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
+            // local-name
+            result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable);
+            qNameTable.push_back(result);
+            return qNameTable.back();
+        }
+        else {
+            // We have an index (C.17.4)
+            size_t index = parseInt2();
+            if (index >= qNameTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            return qNameTable[index];
+        }
+    }
+
+    const QName &parseQualifiedNameOrIndex3(std::vector<QName> &qNameTable) { // C.18
+        uint8_t b = *dataP;
+        if ((b & 0x3c) == 0x3c) { // xx1111..
+            // We have a literal (C.18.3)
+            ++dataP;
+            QName result;
+            // prefix (C.18.3.1)
+            result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
+            // namespace-name (C.18.3.1)
+            result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
+            // local-name
+            result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable);
+            qNameTable.push_back(result);
+            return qNameTable.back();
+        }
+        else {
+            // We have an index (C.18.4)
+            size_t index = parseInt3();
+            if (index >= qNameTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            return qNameTable[index];
+        }
+    }
+
+    std::shared_ptr<const FIValue> parseNonIdentifyingStringOrIndex1(std::vector<std::shared_ptr<const FIValue>> &valueTable) { // C.14
+        uint8_t b = *dataP;
+        if (b == 0xff) { // C.26.2
+            // empty string
+            ++dataP;
+            return EmptyFIString;
+        }
+        else if (b & 0x80) { // C.14.4
+            // We have an index
+            size_t index = parseInt2();
+            if (index >= valueTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            return valueTable[index];
+        }
+        else { // C.14.3
+            // We have a literal
+            std::shared_ptr<const FIValue> result = parseEncodedCharacterString3();
+            if (b & 0x40) { // C.14.3.1
+                valueTable.push_back(result);
+            }
+            return result;
+        }
+    }
+
+    std::shared_ptr<const FIValue> parseNonIdentifyingStringOrIndex3(std::vector<std::shared_ptr<const FIValue>> &valueTable) { // C.15
+        uint8_t b = *dataP;
+        if (b & 0x20) { // C.15.4
+            // We have an index
+            size_t index = parseInt4();
+            if (index >= valueTable.size()) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            return valueTable[index];
+        }
+        else { // C.15.3
+            // We have a literal
+            std::shared_ptr<const FIValue> result = parseEncodedCharacterString5();
+            if (b & 0x10) { // C.15.3.1
+                valueTable.push_back(result);
+            }
+            return result;
+        }
+    }
+
+    void parseElement() {
+        // C.3
+
+        attributes.clear();
+
+        uint8_t b = *dataP;
+        bool hasAttributes = (b & 0x40) != 0; // C.3.3
+        if ((b & 0x3f) == 0x38) { // C.3.4.1
+            // Parse namespaces
+            ++dataP;
+            for (;;) {
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                b = *dataP++;
+                if (b == 0xf0) { // C.3.4.3
+                    break;
+                }
+                if ((b & 0xfc) != 0xcc) { // C.3.4.2
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                // C.12
+                Attribute attr;
+                attr.qname.prefix = "xmlns";
+                attr.qname.name = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
+                attr.qname.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
+                attr.name = attr.qname.name.empty() ? "xmlns" : "xmlns:" + attr.qname.name;
+                attr.value = FIStringValue::create(std::string(attr.qname.uri));
+                attributes.push_back(attr);
+            }
+            if ((dataEnd - dataP < 1) || (*dataP & 0xc0)) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+        }
+
+        // Parse Element name (C.3.5)
+        const QName &elemName = parseQualifiedNameOrIndex3(vocabulary.elementNameTable);
+        nodeName = elemName.prefix.empty() ? elemName.name : elemName.prefix + ':' + elemName.name;
+
+        if (hasAttributes) {
+            for (;;) {
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                b = *dataP;
+                if (b < 0x80) { // C.3.6.1
+                    // C.4
+                    Attribute attr;
+                    attr.qname = parseQualifiedNameOrIndex2(vocabulary.attributeNameTable);
+                    attr.name = attr.qname.prefix.empty() ? attr.qname.name : attr.qname.prefix + ':' + attr.qname.name;
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    attr.value = parseNonIdentifyingStringOrIndex1(vocabulary.attributeValueTable);
+                    attributes.push_back(attr);
+                }
+                else {
+                    if ((b & 0xf0) != 0xf0) { // C.3.6.2
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    emptyElement = b == 0xff; // C.3.6.2, C.3.8
+                    ++dataP;
+                    break;
+                }
+            }
+        }
+        else {
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            b = *dataP;
+            switch (b) {
+            case 0xff:
+                terminatorPending = true;
+                // Intentionally fall through
+            case 0xf0:
+                emptyElement = true;
+                ++dataP;
+                break;
+            default:
+                emptyElement = false;
+            }
+        }
+        if (!emptyElement) {
+            elementStack.push(nodeName);
+        }
+
+        currentNodeType = irr::io::EXN_ELEMENT;
+    }
+
+    void parseHeader() {
+        // Parse header (C.1.3)
+        size_t magicSize = parseMagic(dataP, dataEnd);
+        if (!magicSize) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        dataP += magicSize;
+        // C.2.3
+        if (dataEnd - dataP < 1) {
+            throw DeadlyImportError(parseErrorMessage);
+        }
+        uint8_t b = *dataP++;
+        if (b & 0x40) {
+            // Parse additional data (C.2.4)
+            size_t len = parseSequenceLen();
+            for (size_t i = 0; i < len; ++i) {
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                /*std::string id =*/ parseNonEmptyOctetString2();
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                /*std::string data =*/ parseNonEmptyOctetString2();
+            }
+        }
+        if (b & 0x20) {
+            // Parse initial vocabulary (C.2.5)
+            if (dataEnd - dataP < 2) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            uint16_t b1 = (dataP[0] << 8) | dataP[1];
+            dataP += 2;
+            if (b1 & 0x1000) {
+                // External vocabulary (C.2.5.2)
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                std::string uri = parseNonEmptyOctetString2();
+                auto it = vocabularyMap.find(uri);
+                if (it == vocabularyMap.end()) {
+                    throw DeadlyImportError("Unknown vocabulary " + uri);
+                }
+                const FIVocabulary *externalVocabulary = it->second;
+                if (externalVocabulary->restrictedAlphabetTable) {
+                    std::copy(externalVocabulary->restrictedAlphabetTable, externalVocabulary->restrictedAlphabetTable + externalVocabulary->restrictedAlphabetTableSize, std::back_inserter(vocabulary.restrictedAlphabetTable));
+                }
+                if (externalVocabulary->encodingAlgorithmTable) {
+                    std::copy(externalVocabulary->encodingAlgorithmTable, externalVocabulary->encodingAlgorithmTable + externalVocabulary->encodingAlgorithmTableSize, std::back_inserter(vocabulary.encodingAlgorithmTable));
+                }
+                if (externalVocabulary->prefixTable) {
+                    std::copy(externalVocabulary->prefixTable, externalVocabulary->prefixTable + externalVocabulary->prefixTableSize, std::back_inserter(vocabulary.prefixTable));
+                }
+                if (externalVocabulary->namespaceNameTable) {
+                    std::copy(externalVocabulary->namespaceNameTable, externalVocabulary->namespaceNameTable + externalVocabulary->namespaceNameTableSize, std::back_inserter(vocabulary.namespaceNameTable));
+                }
+                if (externalVocabulary->localNameTable) {
+                    std::copy(externalVocabulary->localNameTable, externalVocabulary->localNameTable + externalVocabulary->localNameTableSize, std::back_inserter(vocabulary.localNameTable));
+                }
+                if (externalVocabulary->otherNCNameTable) {
+                    std::copy(externalVocabulary->otherNCNameTable, externalVocabulary->otherNCNameTable + externalVocabulary->otherNCNameTableSize, std::back_inserter(vocabulary.otherNCNameTable));
+                }
+                if (externalVocabulary->otherURITable) {
+                    std::copy(externalVocabulary->otherURITable, externalVocabulary->otherURITable + externalVocabulary->otherURITableSize, std::back_inserter(vocabulary.otherURITable));
+                }
+                if (externalVocabulary->attributeValueTable) {
+                    std::copy(externalVocabulary->attributeValueTable, externalVocabulary->attributeValueTable + externalVocabulary->attributeValueTableSize, std::back_inserter(vocabulary.attributeValueTable));
+                }
+                if (externalVocabulary->charactersTable) {
+                    std::copy(externalVocabulary->charactersTable, externalVocabulary->charactersTable + externalVocabulary->charactersTableSize, std::back_inserter(vocabulary.charactersTable));
+                }
+                if (externalVocabulary->otherStringTable) {
+                    std::copy(externalVocabulary->otherStringTable, externalVocabulary->otherStringTable + externalVocabulary->otherStringTableSize, std::back_inserter(vocabulary.otherStringTable));
+                }
+                if (externalVocabulary->elementNameTable) {
+                    std::copy(externalVocabulary->elementNameTable, externalVocabulary->elementNameTable + externalVocabulary->elementNameTableSize, std::back_inserter(vocabulary.elementNameTable));
+                }
+                if (externalVocabulary->attributeNameTable) {
+                    std::copy(externalVocabulary->attributeNameTable, externalVocabulary->attributeNameTable + externalVocabulary->attributeNameTableSize, std::back_inserter(vocabulary.attributeNameTable));
+                }
+            }
+            if (b1 & 0x0800) {
+                // Parse restricted alphabets (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.restrictedAlphabetTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0400) {
+                // Parse encoding algorithms (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.encodingAlgorithmTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0200) {
+                // Parse prefixes (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.prefixTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0100) {
+                // Parse namespace names (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.namespaceNameTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0080) {
+                // Parse local names (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.localNameTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0040) {
+                // Parse other ncnames (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.otherNCNameTable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0020) {
+                // Parse other uris (C.2.5.3)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.otherURITable.push_back(parseNonEmptyOctetString2());
+                }
+            }
+            if (b1 & 0x0010) {
+                // Parse attribute values (C.2.5.4)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.attributeValueTable.push_back(parseEncodedCharacterString3());
+                }
+            }
+            if (b1 & 0x0008) {
+                // Parse content character chunks (C.2.5.4)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.charactersTable.push_back(parseEncodedCharacterString3());
+                }
+            }
+            if (b1 & 0x0004) {
+                // Parse other strings (C.2.5.4)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    if (dataEnd - dataP < 1) {
+                        throw DeadlyImportError(parseErrorMessage);
+                    }
+                    vocabulary.otherStringTable.push_back(parseEncodedCharacterString3());
+                }
+            }
+            if (b1 & 0x0002) {
+                // Parse element name surrogates (C.2.5.5)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    vocabulary.elementNameTable.push_back(parseNameSurrogate());
+                }
+            }
+            if (b1 & 0x0001) {
+                // Parse attribute name surrogates (C.2.5.5)
+                for (size_t len = parseSequenceLen(); len > 0; --len) {
+                    vocabulary.attributeNameTable.push_back(parseNameSurrogate());
+                }
+            }
+        }
+        if (b & 0x10) {
+            // Parse notations (C.2.6)
+            for (;;) {
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                uint8_t b1 = *dataP++;
+                if (b1 == 0xf0) {
+                    break;
+                }
+                if ((b1 & 0xfc) != 0xc0) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                /* C.11 */
+                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
+                if (b1 & 0x02) {
+                    /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                if (b1 & 0x01) {
+                    /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+            }
+        }
+        if (b & 0x08) {
+            // Parse unparsed entities (C.2.7)
+            for (;;) {
+                if (dataEnd - dataP < 1) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                uint8_t b1 = *dataP++;
+                if (b1 == 0xf0) {
+                    break;
+                }
+                if ((b1 & 0xfe) != 0xd0) {
+                    throw DeadlyImportError(parseErrorMessage);
+                }
+                /* C.10 */
+                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
+                /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                if (b1 & 0x01) {
+                    /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
+                }
+                /*const std::string &notationName =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
+            }
+        }
+        if (b & 0x04) {
+            // Parse character encoding scheme (C.2.8)
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            /*std::string characterEncodingScheme =*/ parseNonEmptyOctetString2();
+        }
+        if (b & 0x02) {
+            // Parse standalone flag (C.2.9)
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            uint8_t b1 = *dataP++;
+            if (b1 & 0xfe) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            //bool standalone = b1 & 0x01;
+        }
+        if (b & 0x01) {
+            // Parse version (C.2.10)
+            if (dataEnd - dataP < 1) {
+                throw DeadlyImportError(parseErrorMessage);
+            }
+            /*std::shared_ptr<const FIValue> version =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
+        }
+    }
+
+    std::unique_ptr<uint8_t[]> data;
+    uint8_t *dataP, *dataEnd;
+    irr::io::EXML_NODE currentNodeType;
+    bool emptyElement;
+    bool headerPending;
+    bool terminatorPending;
+    Vocabulary vocabulary;
+    std::vector<Attribute> attributes;
+    std::stack<std::string> elementStack;
+    std::string nodeName;
+    std::map<std::string, std::unique_ptr<FIDecoder>> decoderMap;
+    std::map<std::string, const FIVocabulary*> vocabularyMap;
+
+    static const std::string EmptyString;
+    static std::shared_ptr<const FIValue> EmptyFIString;
+
+    static FIHexDecoder hexDecoder;
+    static FIBase64Decoder base64Decoder;
+    static FIShortDecoder shortDecoder;
+    static FIIntDecoder intDecoder;
+    static FILongDecoder longDecoder;
+    static FIBoolDecoder boolDecoder;
+    static FIFloatDecoder floatDecoder;
+    static FIDoubleDecoder doubleDecoder;
+    static FIUUIDDecoder uuidDecoder;
+    static FICDATADecoder cdataDecoder;
+    static FIDecoder *defaultDecoder[32];
+};
+
+const std::string CFIReaderImpl::EmptyString;
+std::shared_ptr<const FIValue> CFIReaderImpl::EmptyFIString = FIStringValue::create(std::string());
+
+FIHexDecoder CFIReaderImpl::hexDecoder;
+FIBase64Decoder CFIReaderImpl::base64Decoder;
+FIShortDecoder CFIReaderImpl::shortDecoder;
+FIIntDecoder CFIReaderImpl::intDecoder;
+FILongDecoder CFIReaderImpl::longDecoder;
+FIBoolDecoder CFIReaderImpl::boolDecoder;
+FIFloatDecoder CFIReaderImpl::floatDecoder;
+FIDoubleDecoder CFIReaderImpl::doubleDecoder;
+FIUUIDDecoder CFIReaderImpl::uuidDecoder;
+FICDATADecoder CFIReaderImpl::cdataDecoder;
+
+FIDecoder *CFIReaderImpl::defaultDecoder[32] = {
+    &hexDecoder,
+    &base64Decoder,
+    &shortDecoder,
+    &intDecoder,
+    &longDecoder,
+    &boolDecoder,
+    &floatDecoder,
+    &doubleDecoder,
+    &uuidDecoder,
+    &cdataDecoder
+};
+
+class CXMLReaderImpl : public FIReader
+{
+public:
+
+    //! Constructor
+    CXMLReaderImpl(std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>> reader_)
+    : reader(std::move(reader_))
+    {}
+
+    virtual ~CXMLReaderImpl() {}
+
+    virtual bool read() /*override*/ {
+        return reader->read();
+    }
+
+    virtual irr::io::EXML_NODE getNodeType() const /*override*/ {
+        return reader->getNodeType();
+    }
+
+    virtual int getAttributeCount() const /*override*/ {
+        return reader->getAttributeCount();
+    }
+
+    virtual const char* getAttributeName(int idx) const /*override*/ {
+        return reader->getAttributeName(idx);
+    }
+
+    virtual const char* getAttributeValue(int idx) const /*override*/ {
+        return reader->getAttributeValue(idx);
+    }
+
+    virtual const char* getAttributeValue(const char* name) const /*override*/ {
+        return reader->getAttributeValue(name);
+    }
+
+    virtual const char* getAttributeValueSafe(const char* name) const /*override*/ {
+        return reader->getAttributeValueSafe(name);
+    }
+
+    virtual int getAttributeValueAsInt(const char* name) const /*override*/ {
+        return reader->getAttributeValueAsInt(name);
+    }
+
+    virtual int getAttributeValueAsInt(int idx) const /*override*/ {
+        return reader->getAttributeValueAsInt(idx);
+    }
+
+    virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
+        return reader->getAttributeValueAsFloat(name);
+    }
+
+    virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
+        return reader->getAttributeValueAsFloat(idx);
+    }
+
+    virtual const char* getNodeName() const /*override*/ {
+        return reader->getNodeName();
+    }
+
+    virtual const char* getNodeData() const /*override*/ {
+        return reader->getNodeData();
+    }
+
+    virtual bool isEmptyElement() const /*override*/ {
+        return reader->isEmptyElement();
+    }
+
+    virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ {
+        return reader->getSourceFormat();
+    }
+
+    virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ {
+        return reader->getParserFormat();
+    }
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const /*override*/ {
+        return nullptr;
+    }
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* name) const /*override*/ {
+        return nullptr;
+    }
+
+    virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) /*override*/ {}
+
+    virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ {}
+
+private:
+
+    std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>> reader;
+};
+
+static std::unique_ptr<uint8_t[]> readFile(IOStream *stream, size_t &size, bool &isFI) {
+    size = stream->FileSize();
+    std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
+    if (stream->Read(data.get(), size, 1) != 1) {
+        size = 0;
+        data.reset();
+    }
+    isFI = parseMagic(data.get(), data.get() + size) > 0;
+    return data;
+}
+
+std::unique_ptr<FIReader> FIReader::create(IOStream *stream)
+{
+    size_t size;
+    bool isFI;
+    auto data = readFile(stream, size, isFI);
+    if (isFI) {
+        return std::unique_ptr<FIReader>(new CFIReaderImpl(std::move(data), size));
+    }
+    else {
+        auto memios = std::unique_ptr<MemoryIOStream>(new MemoryIOStream(data.release(), size, true));
+        auto callback = std::unique_ptr<CIrrXML_IOStreamReader>(new CIrrXML_IOStreamReader(memios.get()));
+        return std::unique_ptr<FIReader>(new CXMLReaderImpl(std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>>(createIrrXMLReader(callback.get()))));
+    }
+}
+
+}// namespace Assimp
+
+#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

+ 172 - 0
code/FIReader.hpp

@@ -0,0 +1,172 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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   FIReader.hpp
+/// \brief  Reader for Fast Infoset encoded binary XML files.
+/// \date   2017
+/// \author Patrick Daehne
+
+#ifndef INCLUDED_AI_FI_READER_H
+#define INCLUDED_AI_FI_READER_H
+
+#include <irrXML.h>
+#include <memory>
+#include <string>
+#include <vector>
+#include <cstdint>
+
+namespace Assimp {
+
+struct FIValue {
+    virtual const std::string &toString() const = 0;
+};
+
+struct FIStringValue: public FIValue {
+    std::string value;
+    static std::shared_ptr<FIStringValue> create(std::string &&value);
+};
+
+struct FIByteValue: public FIValue {
+    std::vector<uint8_t> value;
+};
+
+struct FIHexValue: public FIByteValue {
+    static std::shared_ptr<FIHexValue> create(std::vector<uint8_t> &&value);
+};
+
+struct FIBase64Value: public FIByteValue {
+    static std::shared_ptr<FIBase64Value> create(std::vector<uint8_t> &&value);
+};
+
+struct FIShortValue: public FIValue {
+    std::vector<int16_t> value;
+    static std::shared_ptr<FIShortValue> create(std::vector<int16_t> &&value);
+};
+
+struct FIIntValue: public FIValue {
+    std::vector<int32_t> value;
+    static std::shared_ptr<FIIntValue> create(std::vector<int32_t> &&value);
+};
+
+struct FILongValue: public FIValue {
+    std::vector<int64_t> value;
+    static std::shared_ptr<FILongValue> create(std::vector<int64_t> &&value);
+};
+
+struct FIBoolValue: public FIValue {
+    std::vector<bool> value;
+    static std::shared_ptr<FIBoolValue> create(std::vector<bool> &&value);
+};
+
+struct FIFloatValue: public FIValue {
+    std::vector<float> value;
+    static std::shared_ptr<FIFloatValue> create(std::vector<float> &&value);
+};
+
+struct FIDoubleValue: public FIValue {
+    std::vector<double> value;
+    static std::shared_ptr<FIDoubleValue> create(std::vector<double> &&value);
+};
+
+struct FIUUIDValue: public FIByteValue {
+    static std::shared_ptr<FIUUIDValue> create(std::vector<uint8_t> &&value);
+};
+
+struct FICDATAValue: public FIStringValue {
+    static std::shared_ptr<FICDATAValue> create(std::string &&value);
+};
+
+struct FIDecoder {
+    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) = 0;
+};
+
+struct FIQName {
+    const char *name;
+    const char *prefix;
+    const char *uri;
+};
+
+struct FIVocabulary {
+    const char **restrictedAlphabetTable;
+    size_t restrictedAlphabetTableSize;
+    const char **encodingAlgorithmTable;
+    size_t encodingAlgorithmTableSize;
+    const char **prefixTable;
+    size_t prefixTableSize;
+    const char **namespaceNameTable;
+    size_t namespaceNameTableSize;
+    const char **localNameTable;
+    size_t localNameTableSize;
+    const char **otherNCNameTable;
+    size_t otherNCNameTableSize;
+    const char **otherURITable;
+    size_t otherURITableSize;
+    const std::shared_ptr<const FIValue> *attributeValueTable;
+    size_t attributeValueTableSize;
+    const std::shared_ptr<const FIValue> *charactersTable;
+    size_t charactersTableSize;
+    const std::shared_ptr<const FIValue> *otherStringTable;
+    size_t otherStringTableSize;
+    const FIQName *elementNameTable;
+    size_t elementNameTableSize;
+    const FIQName *attributeNameTable;
+    size_t attributeNameTableSize;
+};
+
+class IOStream;
+
+class FIReader: public irr::io::IIrrXMLReader<char, irr::io::IXMLBase> {
+public:
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const = 0;
+
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char *name) const = 0;
+
+    virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) = 0;
+
+    virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) = 0;
+
+    static std::unique_ptr<FIReader> create(IOStream *stream);
+
+};// class IFIReader
+
+}// namespace Assimp
+
+#endif // INCLUDED_AI_FI_READER_H

+ 2 - 3
code/HalfLifeFileData.h

@@ -66,8 +66,7 @@ namespace MDL   {
  *  \brief Data structure for the HL2 main header
  */
 // ---------------------------------------------------------------------------
-struct Header_HL2
-{
+struct Header_HL2 {
     //! magic number: "IDST"/"IDSQ"
     char    ident[4];
 
@@ -139,7 +138,7 @@ struct Header_HL2
     //! Number of animation transitions
     int32_t         numtransitions;
     int32_t         transitionindex;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 #include "./../include/assimp/Compiler/poppack1.h"
 

+ 1 - 1
code/IRRLoader.cpp

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "fast_atof.h"
 #include "GenericProperty.h"
 
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "StandardShapes.h"
 #include "Importer.h"
 

+ 1 - 1
code/IRRLoader.h

@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_IRRLOADER_H_INCLUDED
 
 #include "IRRShared.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Importer.h"
 #include "StringUtils.h"
 #include <assimp/anim.h>

+ 2 - 0
code/ImporterRegistry.cpp

@@ -231,7 +231,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
     out.push_back( new MDLImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER)
+  #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
     out.push_back( new ASEImporter());
+#  endif
 #endif
 #if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER)
     out.push_back( new HMPImporter());

+ 2 - 1
code/LWOAnimation.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "LWOFileData.h"
+#include <assimp/anim.h>
 
 using namespace Assimp;
 using namespace Assimp::LWO;
@@ -163,7 +164,7 @@ void AnimResolver::UpdateAnimRangeSetup()
                 {
                 const double start_time = delta - std::fmod(my_first-first,delta);
                 std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(),
-                    std::bind1st(std::greater<double>(),start_time)),m;
+                    [start_time](double t) { return start_time > t; }),m;
 
                 size_t ofs = 0;
                 if (n != (*it).keys.end()) {

+ 3 - 4
code/LWOAnimation.h

@@ -48,11 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_LWO_ANIMATION_INCLUDED
 #define AI_LWO_ANIMATION_INCLUDED
 
-#include <assimp/anim.h>
+//
 #include <vector>
 #include <list>
 
 struct aiNodeAnim;
+struct aiVectorKey;
 
 namespace Assimp {
 namespace LWO {
@@ -166,7 +167,6 @@ struct Envelope
     //! Keyframes for this envelope
     std::vector<Key> keys;
 
-
     // temporary data for AnimResolver
     size_t old_first,old_last;
 };
@@ -198,8 +198,7 @@ public:
      *  @param Output tick rate, per second
      *  @note The input envelopes are possibly modified.
      */
-    AnimResolver(std::list<Envelope>& envelopes,
-        double tick);
+    AnimResolver(std::list<Envelope>& envelopes, double tick);
 
 public:
 

+ 1 - 1
code/LWSLoader.cpp

@@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ParsingUtils.h"
 #include "fast_atof.h"
 
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "GenericProperty.h"
 #include "SkeletonMeshBuilder.h"
 #include "ConvertToLHProcess.h"

+ 1 - 1
code/LWSLoader.h

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_LWSLOADER_H_INCLUDED
 
 #include "LWOFileData.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "BaseImporter.h"
 
 struct aiImporterDesc;

+ 12 - 15
code/MD3FileData.h

@@ -142,14 +142,14 @@ struct Frame
     //! name of frame
     char name[ AI_MD3_MAXFRAME ];
 
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------
-/** @brief Data structure for the tag header
+/**
+ * @brief Data structure for the tag header
  */
-struct Tag
-{
+struct Tag {
     //! name of the tag
     char NAME[ AI_MD3_MAXQPATH ];
 
@@ -157,14 +157,13 @@ struct Tag
     aiVector3D  origin;
     ai_real  orientation[3][3];
 
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------
 /** @brief Data structure for the surface header
  */
-struct Surface
-{
+struct Surface {
     //! magic number
     int32_t IDENT;
 
@@ -186,7 +185,6 @@ struct Surface
     //! number of triangles in the surface
     uint32_t NUM_TRIANGLES;
 
-
     //! offset to the triangle data
     uint32_t OFS_TRIANGLES;
 
@@ -201,19 +199,18 @@ struct Surface
 
     //! offset to the end of the Surface object
     int32_t OFS_END;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 // -------------------------------------------------------------------------------
 /** @brief Data structure for a shader defined in there
  */
-struct Shader
-{
+struct Shader {
     //! filename of the shader
     char NAME[ AI_MD3_MAXQPATH ];
 
     //! index of the shader
     uint32_t SHADER_INDEX;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 
 // -------------------------------------------------------------------------------
@@ -223,7 +220,7 @@ struct Triangle
 {
     //! triangle indices
     uint32_t INDEXES[3];
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 
 // -------------------------------------------------------------------------------
@@ -233,7 +230,7 @@ struct TexCoord
 {
     //! UV coordinates
     ai_real U,V;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 
 // -------------------------------------------------------------------------------
@@ -246,7 +243,7 @@ struct Vertex
 
     //! encoded normal vector
     uint16_t  NORMAL;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 #include "./../include/assimp/Compiler/poppack1.h"
 

+ 1 - 1
code/MD3Loader.cpp

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER
 
 #include "MD3Loader.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "GenericProperty.h"
 #include "RemoveComments.h"
 #include "ParsingUtils.h"

+ 1 - 1
code/MDCFileData.h

@@ -157,7 +157,7 @@ struct Frame
 
     //! Name of the frame
     char name [ 16 ] ;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC triangle

+ 51 - 76
code/MDLFileData.h

@@ -53,10 +53,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_MDLFILEHELPER_H_INC
 #define AI_MDLFILEHELPER_H_INC
 
+#include <assimp/anim.h>
+#include <assimp/mesh.h>
+#include <assimp/Compiler/pushpack1.h>
 #include "ByteSwapper.h"
-#include "./../include/assimp/anim.h"
-#include "./../include/assimp/mesh.h"
-#include "./../include/assimp/Compiler/pushpack1.h"
 #include <stdint.h>
 #include <vector>
 
@@ -90,7 +90,6 @@ namespace MDL   {
 #define AI_MDL_MAGIC_NUMBER_BE_GS7  AI_MAKE_MAGIC("MDL7")
 #define AI_MDL_MAGIC_NUMBER_LE_GS7  AI_MAKE_MAGIC("7LDM")
 
-
 // common limitations for Quake1 meshes. The loader does not check them,
 // (however it warns) but models should not exceed these limits.
 #if (!defined AI_MDL_VERSION)
@@ -119,8 +118,7 @@ namespace MDL   {
 /** \struct Header
  *  \brief Data structure for the MDL main header
  */
-struct Header
-{
+struct Header {
     //! magic number: "IDPO"
     uint32_t ident;
 
@@ -166,15 +164,14 @@ struct Header
 
     //! Could be the total size of the file (and not a float)
     float size;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
 /** \struct Header_MDL7
  *  \brief Data structure for the MDL 7 main header
  */
-struct Header_MDL7
-{
+struct Header_MDL7 {
     //! magic number: "MDL7"
     char    ident[4];
 
@@ -226,15 +223,14 @@ struct Header_MDL7
 
     //! Size of the Frame_MDL7 data structure used in the file
     uint16_t frame_stc_size;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
 /** \struct Bone_MDL7
  *  \brief Data structure for a bone in a MDL7 file
  */
-struct Bone_MDL7
-{
+struct Bone_MDL7 {
     //! Index of the parent bone of *this* bone. 0xffff means:
     //! "hey, I have no parent, I'm an orphan"
     uint16_t parent_index;
@@ -246,7 +242,7 @@ struct Bone_MDL7
 
     //! Optional name of the bone
     char name[1 /* DUMMY SIZE */];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 #if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS)
 #   define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS (16 + 20)
@@ -268,8 +264,7 @@ struct Bone_MDL7
 /** \struct Group_MDL7
  *  \brief Group in a MDL7 file
  */
-struct Group_MDL7
-{
+struct Group_MDL7 {
     //! = '1' -> triangle based Mesh
     unsigned char   typ;
 
@@ -295,7 +290,7 @@ struct Group_MDL7
 
     //! Number of frames
     int32_t numframes;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 #define AI_MDL7_SKINTYPE_MIPFLAG                0x08
 #define AI_MDL7_SKINTYPE_MATERIAL               0x10
@@ -310,41 +305,36 @@ struct Group_MDL7
 /** \struct Deformer_MDL7
  *  \brief Deformer in a MDL7 file
  */
-struct Deformer_MDL7
-{
+struct Deformer_MDL7 {
     int8_t  deformer_version;       // 0
     int8_t  deformer_typ;           // 0 - bones
     int8_t  _unused_[2];
     int32_t group_index;
     int32_t elements;
     int32_t deformerdata_size;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
 /** \struct DeformerElement_MDL7
  *  \brief Deformer element in a MDL7 file
  */
-struct DeformerElement_MDL7
-{
+struct DeformerElement_MDL7 {
     //! bei deformer_typ==0 (==bones) element_index == bone index
     int32_t element_index;
     char    element_name[AI_MDL7_MAX_BONENAMESIZE];
     int32_t weights;
-} PACK_STRUCT;
-
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct DeformerWeight_MDL7
  *  \brief Deformer weight in a MDL7 file
  */
-struct DeformerWeight_MDL7
-{
+struct DeformerWeight_MDL7 {
     //! for deformer_typ==0 (==bones) index == vertex index
     int32_t index;
     float   weight;
-} PACK_STRUCT;
-
+} /* PACK_STRUCT */;
 
 // don't know why this was in the original headers ...
 typedef int32_t MD7_MATERIAL_ASCDEFSIZE;
@@ -353,17 +343,15 @@ typedef int32_t MD7_MATERIAL_ASCDEFSIZE;
 /** \struct ColorValue_MDL7
  *  \brief Data structure for a color value in a MDL7 file
  */
-struct ColorValue_MDL7
-{
+struct ColorValue_MDL7 {
     float r,g,b,a;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Material_MDL7
  *  \brief Data structure for a Material in a MDL7 file
  */
-struct Material_MDL7
-{
+struct Material_MDL7 {
     //! Diffuse base color of the material
     ColorValue_MDL7 Diffuse;
 
@@ -378,15 +366,13 @@ struct Material_MDL7
 
     //! Phong power
     float           Power;
-} PACK_STRUCT;
-
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Skin
  *  \brief Skin data structure #1 - used by Quake1, MDL2, MDL3 and MDL4
  */
-struct Skin
-{
+struct Skin {
     //! 0 = single (Skin), 1 = group (GroupSkin)
     //! For MDL3-5: Defines the type of the skin and there
     //! fore the size of the data to skip:
@@ -402,7 +388,7 @@ struct Skin
 
     //! Texture data
     uint8_t *data;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
@@ -410,11 +396,10 @@ struct Skin
  *  \brief Skin data structure #2 - used by MDL5, MDL6 and MDL7
  *  \see Skin
  */
-struct Skin_MDL5
-{
+struct Skin_MDL5 {
     int32_t size, width, height;
     uint8_t *data;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // maximum length of texture file name
 #if (!defined AI_MDL7_MAX_TEXNAMESIZE)
@@ -425,44 +410,40 @@ struct Skin_MDL5
 /** \struct Skin_MDL7
  *  \brief Skin data structure #3 - used by MDL7 and HMP7
  */
-struct Skin_MDL7
-{
+struct Skin_MDL7 {
     uint8_t         typ;
     int8_t          _unused_[3];
     int32_t         width;
     int32_t         height;
     char            texture_name[AI_MDL7_MAX_TEXNAMESIZE];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct RGB565
  *  \brief Data structure for a RGB565 pixel in a texture
  */
-struct RGB565
-{
+struct RGB565 {
     uint16_t r : 5;
     uint16_t g : 6;
     uint16_t b : 5;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct ARGB4
  *  \brief Data structure for a ARGB4444 pixel in a texture
  */
-struct ARGB4
-{
+struct ARGB4 {
     uint16_t a : 4;
     uint16_t r : 4;
     uint16_t g : 4;
     uint16_t b : 4;
-} PACK_STRUCT;
+} /*PACK_STRUCT*/;
 
 // -------------------------------------------------------------------------------------
 /** \struct GroupSkin
  *  \brief Skin data structure #2 (group of pictures)
  */
-struct GroupSkin
-{
+struct GroupSkin {
     //! 0 = single (Skin), 1 = group (GroupSkin)
     int32_t group;
 
@@ -474,14 +455,13 @@ struct GroupSkin
 
     //! Data of each image
     uint8_t **data;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct TexCoord
  *  \brief Texture coordinate data structure used by the Quake1 MDL format
  */
-struct TexCoord
-{
+struct TexCoord {
     //! Is the vertex on the noundary between front and back piece?
     int32_t onseam;
 
@@ -490,33 +470,31 @@ struct TexCoord
 
     //! Texture coordinate in the ty direction
     int32_t t;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct TexCoord_MDL3
  *  \brief Data structure for an UV coordinate in the 3DGS MDL3 format
  */
-struct TexCoord_MDL3
-{
+struct TexCoord_MDL3 {
     //! position, horizontally in range 0..skinwidth-1
     int16_t u;
 
     //! position, vertically in range 0..skinheight-1
     int16_t v;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct TexCoord_MDL7
  *  \brief Data structure for an UV coordinate in the 3DGS MDL7 format
  */
-struct TexCoord_MDL7
-{
+struct TexCoord_MDL7 {
     //! position, horizontally in range 0..1
     float u;
 
     //! position, vertically in range 0..1
     float v;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct SkinSet_MDL7
@@ -532,7 +510,7 @@ struct SkinSet_MDL7
 
     //! Material index
     int32_t     material;    // size 4
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Triangle
@@ -545,7 +523,7 @@ struct Triangle
 
     //! Vertex indices
     int32_t vertex[3];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Triangle_MDL3
@@ -558,7 +536,7 @@ struct Triangle_MDL3
 
     //! Index of 3 skin vertices in range 0..numskinverts
     uint16_t index_uv[3];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Triangle_MDL7
@@ -571,7 +549,7 @@ struct Triangle_MDL7
 
     //! Two skinsets. The second will be used for multi-texturing
     SkinSet_MDL7  skinsets[2];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 #if (!defined AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV)
 #   define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV (6+sizeof(SkinSet_MDL7)-sizeof(uint32_t))
@@ -599,7 +577,7 @@ struct Vertex
 {
     uint8_t v[3];
     uint8_t normalIndex;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
@@ -625,8 +603,7 @@ struct Vertex_MDL7
         uint8_t norm162index;
         float norm[3];
     };
-} PACK_STRUCT;
-
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct BoneTransform_MDL7
@@ -643,12 +620,11 @@ struct BoneTransform_MDL7
     //! I HATE 3DGS AND THE SILLY DEVELOPER WHO DESIGNED
     //! THIS STUPID FILE FORMAT!
     int8_t _unused_[2];
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 #define AI_MDL7_MAX_FRAMENAMESIZE       16
 
-
 // -------------------------------------------------------------------------------------
 /** \struct Frame_MDL7
  *  \brief Frame data structure used by MDL7 files
@@ -678,7 +654,7 @@ struct SimpleFrame
 
     //! Vertex list of the frame
     Vertex *verts;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct Frame
@@ -691,7 +667,7 @@ struct Frame
 
     //! Frame data
     SimpleFrame frame;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 
 // -------------------------------------------------------------------------------------
@@ -708,7 +684,7 @@ struct SimpleFrame_MDLn_SP
 
     //! Vertex list of the frame
     Vertex_MDL4 *verts;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 // -------------------------------------------------------------------------------------
 /** \struct GroupFrame
@@ -730,7 +706,7 @@ struct GroupFrame
 
     //! List of single frames
     SimpleFrame *frames;
-} PACK_STRUCT;
+} /* PACK_STRUCT */;
 
 #include "./../include/assimp/Compiler/poppack1.h"
 
@@ -738,8 +714,7 @@ struct GroupFrame
 /** \struct IntFace_MDL7
  *  \brief Internal data structure to temporarily represent a face
  */
-struct IntFace_MDL7
-{
+struct IntFace_MDL7 {
     // provide a constructor for our own convenience
     IntFace_MDL7()
     {

+ 12 - 23
code/ObjFileParser.cpp

@@ -109,28 +109,6 @@ ObjFile::Model *ObjFileParser::GetModel() const {
     return m_pModel;
 }
 
-/*void ignoreNewLines(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer)
-{
-    auto curPosition = buffer.begin();
-    do
-    {
-        while (*curPosition!='\n'&&*curPosition!='\\')
-        {
-            ++curPosition;
-        }
-        if (*curPosition=='\\')
-        {
-            std::vector<char> tempBuf;
-            do
-            {
-                streamBuffer.getNextDataLine(tempBuf, '\\' );
-            } while (tempBuf[0]=='\n');
-            *curPosition = ' ';
-            std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition);
-        }
-    } while (*curPosition!='\n');
-}*/
-
 void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     // only update every 100KB or it'll be too slow
     //const unsigned int updateProgressEveryBytes = 100 * 1024;
@@ -201,7 +179,18 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
 
         case 'u': // Parse a material desc. setter
             {
-                getMaterialDesc();
+                std::string name;
+
+                getNameNoSpace(m_DataIt, m_DataItEnd, name);
+
+                size_t nextSpace = name.find(" ");
+                if (nextSpace != std::string::npos)
+                    name = name.substr(0, nextSpace);
+
+                if(name == "usemtl")
+                {
+                    getMaterialDesc();
+                }
             }
             break;
 

+ 4 - 4
code/OgreParsingUtils.h

@@ -91,11 +91,11 @@ static inline std::string &TrimLeft(std::string &s, bool newlines = true)
 {
     if (!newlines)
     {
-        s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpace<char>))));
+        s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
     }
     else
     {
-        s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine<char>))));
+        s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     return s;
 }
@@ -105,11 +105,11 @@ static inline std::string &TrimRight(std::string &s, bool newlines = true)
 {
     if (!newlines)
     {
-        s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(Assimp::IsSpace<char>))).base(),s.end());
+        s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
     }
     else
     {
-        s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine<char>))));
+        s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     return s;
 }

+ 1 - 1
code/OptimizeGraph.cpp

@@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "OptimizeGraph.h"
 #include "ProcessHelper.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Exceptional.h"
 #include <stdio.h>
 

+ 1 - 1
code/OptimizeMeshes.cpp

@@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "OptimizeMeshes.h"
 #include "ProcessHelper.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Exceptional.h"
 
 using namespace Assimp;

+ 3 - 0
code/PlyLoader.cpp

@@ -159,6 +159,9 @@ void PLYImporter::InternReadFile(const std::string& pFile,
 
   // Get the file-size
   size_t fileSize = fileStream->FileSize();
+  if ( 0 == fileSize ) {
+      throw DeadlyImportError("File " + pFile + " is empty.");
+  }
 
   IOStreamBuffer<char> streamedBuffer(1024 * 1024);
   streamedBuffer.open(fileStream.get());

+ 5 - 24
code/PlyParser.cpp

@@ -935,30 +935,6 @@ bool PLY::PropertyInstance::ParseValue(const char* &pCur,
   ai_assert(NULL != out);
   
   //calc element size
-  unsigned int lsize = 0;
-  switch (eType)
-  {
-  case EDT_Char:
-  case EDT_UChar:
-    lsize = 1;
-    break;
-
-  case EDT_UShort:
-  case EDT_Short:
-    lsize = 2;
-    break;
-
-  case EDT_UInt:
-  case EDT_Int:
-  case EDT_Float:
-    lsize = 4;
-    break;
-
-  case EDT_Double:
-    lsize = 8;
-    break;
-  }
-
   bool ret = true;
   switch (eType)
   {
@@ -990,6 +966,7 @@ bool PLY::PropertyInstance::ParseValue(const char* &pCur,
     out->fDouble = (double)d;
     break;
 
+  case EDT_INVALID:
   default:
     ret = false;
     break;
@@ -1032,6 +1009,10 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
   case EDT_Double:
     lsize = 8;
     break;
+
+  case EDT_INVALID:
+  default:
+      break;
   }
 
   //read the next file block if needed

+ 1 - 1
code/PretransformVertices.cpp

@@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "PretransformVertices.h"
 #include "ProcessHelper.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Exceptional.h"
 
 using namespace Assimp;

+ 1 - 1
code/SceneCombiner.cpp

@@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *       OptimizeGraph step.
   */
 // ----------------------------------------------------------------------------
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "StringUtils.h"
 #include "fast_atof.h"
 #include "Hash.h"

+ 2 - 1
code/StepExporter.cpp

@@ -43,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
+
 #include "StepExporter.h"
 #include "ConvertToLHProcess.h"
 #include "Bitmap.h"
 #include "BaseImporter.h"
 #include "fast_atof.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include <iostream>
 #include <ctime>
 #include <set>

+ 1 - 1
code/Subdivision.cpp

@@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "Subdivision.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "SpatialSort.h"
 #include "ProcessHelper.h"
 #include "Vertex.h"

+ 2 - 2
code/X3DExporter.cpp

@@ -140,7 +140,7 @@ void X3DExporter::AttrHelper_Col3DArrToString(const aiColor3D* pArray, const siz
 	AttrHelper_CommaToPoint(pTargetString);
 }
 
-void X3DExporter::AttrHelper_Color3ToAttrList(std::list<SAttribute> pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue)
+void X3DExporter::AttrHelper_Color3ToAttrList(std::list<SAttribute>& pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue)
 {
 string tstr;
 
@@ -150,7 +150,7 @@ string tstr;
 	pList.push_back({pName, tstr});
 }
 
-void X3DExporter::AttrHelper_FloatToAttrList(std::list<SAttribute> pList, const string& pName, const float pValue, const float pDefaultValue)
+void X3DExporter::AttrHelper_FloatToAttrList(std::list<SAttribute>& pList, const string& pName, const float pValue, const float pDefaultValue)
 {
 string tstr;
 

+ 2 - 2
code/X3DExporter.hpp

@@ -134,7 +134,7 @@ private:
 
 	/// \fn void AttrHelper_FloatToAttrList(std::list<SAttribute> pList, const std::string& pName, const float pValue, const float pDefaultValue)
 	/// \overload void AttrHelper_Col3DArrToString(const aiColor3D* pArray, const size_t pArray_Size, std::string& pTargetString)
-	void AttrHelper_FloatToAttrList(std::list<SAttribute> pList, const std::string& pName, const float pValue, const float pDefaultValue);
+	void AttrHelper_FloatToAttrList(std::list<SAttribute> &pList, const std::string& pName, const float pValue, const float pDefaultValue);
 
 	/// \fn void AttrHelper_Color3ToAttrList(std::list<SAttribute> pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue)
 	/// Add attribute to list if value not equal to default.
@@ -142,7 +142,7 @@ private:
 	/// \param [in] pName - name of new attribute.
 	/// \param [in] pValue - value of the new attribute.
 	/// \param [in] pDefaultValue - default value for checking: if pValue is equal to pDefaultValue then attribute will not be added.
-	void AttrHelper_Color3ToAttrList(std::list<SAttribute> pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue);
+	void AttrHelper_Color3ToAttrList(std::list<SAttribute> &pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue);
 
 	/// \fn void NodeHelper_OpenNode(const std::string& pNodeName, const size_t pTabLevel, const bool pEmptyElement, const std::list<SAttribute>& pAttrList)
 	/// Begin new XML-node element.

+ 211 - 222
code/X3DImporter.cpp

@@ -52,10 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // Header files, Assimp.
 #include <assimp/DefaultIOSystem.h>
 #include "fast_atof.h"
+#include "FIReader.hpp"
 
 // Header files, stdlib.
 #include <memory>
 #include <string>
+#include <iterator>
 
 namespace Assimp {
 
@@ -66,14 +68,53 @@ const aiImporterDesc X3DImporter::Description = {
 	"smalcom",
 	"",
 	"See documentation in source code. Chapter: Limitations.",
-	aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
+	aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
 	0,
 	0,
 	0,
 	0,
-	"x3d"
+	"x3d x3db"
 };
 
+//const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)");
+//const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase);
+
+struct WordIterator: public std::iterator<std::input_iterator_tag, const char*> {
+    static const char *whitespace;
+    const char *start_, *end_;
+    WordIterator(const char *start, const char *end): start_(start), end_(end) {
+        start_ = start + strspn(start, whitespace);
+        if (start_ >= end_) {
+            start_ = 0;
+        }
+    }
+    WordIterator(): start_(0), end_(0) {}
+    WordIterator(const WordIterator &other): start_(other.start_), end_(other.end_) {}
+    WordIterator &operator=(const WordIterator &other) {
+        start_ = other.start_;
+        end_ = other.end_;
+        return *this;
+    }
+    bool operator==(WordIterator &other) const { return start_ == other.start_; }
+    bool operator!=(WordIterator &other) const { return start_ != other.start_; }
+    WordIterator &operator++() {
+        start_ += strcspn(start_, whitespace);
+        start_ += strspn(start_, whitespace);
+        if (start_ >= end_) {
+            start_ = 0;
+        }
+        return *this;
+    }
+    WordIterator operator++(int) {
+        WordIterator result(*this);
+        ++(*this);
+        return result;
+    }
+    const char *operator*() const { return start_; }
+};
+
+const char *WordIterator::whitespace = ", \t\r\n";
+
 X3DImporter::X3DImporter()
 : NodeElement_Cur( nullptr )
 , mReader( nullptr ) {
@@ -81,7 +122,6 @@ X3DImporter::X3DImporter()
 }
 
 X3DImporter::~X3DImporter() {
-    delete mReader;
     // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
     Clear();
 }
@@ -241,7 +281,7 @@ void X3DImporter::XML_CheckNode_MustBeEmpty()
 
 void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
 {
-    static const size_t Uns_Skip_Len = 190;
+    static const size_t Uns_Skip_Len = 192;
     const char* Uns_Skip[ Uns_Skip_Len ] = {
 	    // CAD geometry component
 	    "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet",
@@ -276,7 +316,7 @@ void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeNa
 	    // Navigation component
 	    "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup",
 	    // Networking component
-	    "Anchor", "LoadSensor",
+	    "EXPORT", "IMPORT", "Anchor", "LoadSensor",
 	    // NURBS component
 	    "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
 	    "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
@@ -368,38 +408,65 @@ bool X3DImporter::XML_SearchNode(const std::string& pNodeName)
 
 bool X3DImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
 {
-std::string val(mReader->getAttributeValue(pAttrIdx));
-
-	if(val == "false")
-		return false;
-	else if(val == "true")
-		return true;
-	else
-		throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\"");
+    auto boolValue = std::dynamic_pointer_cast<const FIBoolValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (boolValue) {
+        if (boolValue->value.size() == 1) {
+            return boolValue->value.front();
+        }
+        throw DeadlyImportError("Invalid bool value");
+    }
+    else {
+        std::string val(mReader->getAttributeValue(pAttrIdx));
+
+        if(val == "false")
+            return false;
+        else if(val == "true")
+            return true;
+        else
+            throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\"");
+    }
 }
 
 float X3DImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
 {
-    std::string val;
-    float tvalf;
+    auto floatValue = std::dynamic_pointer_cast<const FIFloatValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (floatValue) {
+        if (floatValue->value.size() == 1) {
+            return floatValue->value.front();
+        }
+        throw DeadlyImportError("Invalid float value");
+    }
+    else {
+        std::string val;
+        float tvalf;
 
-	ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
-	fast_atoreal_move(val.c_str(), tvalf, false);
+        ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
+        fast_atoreal_move(val.c_str(), tvalf, false);
 
-	return tvalf;
+        return tvalf;
+    }
 }
 
 int32_t X3DImporter::XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx)
 {
-	return strtol10(mReader->getAttributeValue(pAttrIdx));
+    auto intValue = std::dynamic_pointer_cast<const FIIntValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (intValue) {
+        if (intValue->value.size() == 1) {
+            return intValue->value.front();
+        }
+        throw DeadlyImportError("Invalid int value");
+    }
+    else {
+        return strtol10(mReader->getAttributeValue(pAttrIdx));
+    }
 }
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue)
 {
-    std::list<float> tlist;
-    std::list<float>::iterator it;
+    std::vector<float> tlist;
+    std::vector<float>::iterator it;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);
 	if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
 
 	it = tlist.begin();
@@ -410,10 +477,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D&
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue)
 {
-    std::list<float> tlist;
-    std::list<float>::iterator it;
+    std::vector<float> tlist;
+    std::vector<float>::iterator it;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);
 	if(tlist.size() != 2) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
 
 	it = tlist.begin();
@@ -423,10 +490,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue)
 {
-    std::list<float> tlist;
-    std::list<float>::iterator it;
+    std::vector<float> tlist;
+    std::vector<float>::iterator it;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);
 	if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
 
 	it = tlist.begin();
@@ -435,181 +502,95 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D
 	pValue.z = *it;
 }
 
-void X3DImporter::XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list<bool>& pValue)
-{
-	// make copy of attribute value - string with list of bool values. Also all bool values is strings.
-	size_t tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx));
-    if ( 0 == tok_str_len ) {
-        Throw_IncorrectAttrValue( mReader->getAttributeName( pAttrIdx ) );
-    }
-
-	tok_str_len++;// take in account terminating '\0'.
-	char *tok_str = new char[tok_str_len];
-
-	strcpy(tok_str, mReader->getAttributeValue(pAttrIdx));
-	// change all spacebars to symbol '\0'. That is needed for parsing.
-	for(size_t i = 0; i < tok_str_len; i++)
-	{
-		if(tok_str[i] == ' ') tok_str[i] = 0;
-	}
-
-	// at now check what current token is
-	for(char *tok_cur = tok_str, *tok_end = (tok_str + tok_str_len); tok_cur < tok_end;)
-	{
-		if(strncmp(tok_cur, "true", 4) == 0)
-		{
-			pValue.push_back(true);
-			tok_cur += 5;// five, not four. Because '\0' must be skipped too.
-		}
-		else if(strncmp(tok_cur, "false", 5) == 0)
-		{
-			pValue.push_back(true);
-			tok_cur += 6;// six, not five. Because '\0' must be skipped too.
-		}
-		else
-		{
-			Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx));
-		}
-	}// for(char* tok_cur = tok_str, tok_end = (tok_str + tok_str_len); tok_cur < tok_end;)
-
-	// delete temporary string
-	delete [] tok_str;
-}
-
 void X3DImporter::XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector<bool>& pValue)
 {
-    std::list<bool> tlist;
-
-	XML_ReadNode_GetAttrVal_AsListB(pAttrIdx, tlist);// read as list
-	// and copy to array
-	if(tlist.size() > 0)
-	{
-		pValue.reserve(tlist.size());
-		for(std::list<bool>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
-	}
-}
-
-void X3DImporter::XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list<int32_t>& pValue)
-{
-    const char* tstr = mReader->getAttributeValue(pAttrIdx);
-    const char* tstr_end = tstr + strlen(tstr);
-
-	do
-	{
-		const char* ostr;
-
-		int32_t tval32;
-
-		tval32 = strtol10(tstr, &ostr);
-		if(ostr == tstr) break;
+    auto boolValue = std::dynamic_pointer_cast<const FIBoolValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (boolValue) {
+        pValue = boolValue->value;
+    }
+    else {
+        const char *val = mReader->getAttributeValue(pAttrIdx);
+        pValue.clear();
 
-		while((ostr < tstr_end) && (*ostr == ' ')) ostr++;// skip spaces between values.
+        //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws);
+        //const std::cregex_iterator wordItEnd;
+        //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::regex_match(match.str(), pattern_true); });
 
-		tstr = ostr;
-		pValue.push_back(tval32);
-	} while(tstr < tstr_end);
+        WordIterator wordItBegin(val, val + strlen(val));
+        WordIterator wordItEnd;
+        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return (::tolower(match[0]) == 't') || (match[0] == '1'); });
+    }
 }
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector<int32_t>& pValue)
 {
-    std::list<int32_t> tlist;
-
-	XML_ReadNode_GetAttrVal_AsListI32(pAttrIdx, tlist);// read as list
-	// and copy to array
-	if(tlist.size() > 0)
-	{
-		pValue.reserve(tlist.size());
-		for(std::list<int32_t>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
-	}
-}
-
-void X3DImporter::XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list<float>& pValue)
-{
-    std::string str_fixed;
-
-	// at first check string values like '.xxx'.
-	ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed);
-	if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
-
-	// and convert all values and place it in list.
-	const char* pstr = str_fixed.c_str();
-	const char* pstr_end = pstr + str_fixed.size();
-
-	do
-	{
-		float tvalf;
+    auto intValue = std::dynamic_pointer_cast<const FIIntValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (intValue) {
+        pValue = intValue->value;
+    }
+    else {
+        const char *val = mReader->getAttributeValue(pAttrIdx);
+        pValue.clear();
 
-		while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values.
+        //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws);
+        //const std::cregex_iterator wordItEnd;
+        //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stoi(match.str()); });
 
-		if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces.
-		{
-			pstr = fast_atoreal_move(pstr, tvalf, false);
-			pValue.push_back(tvalf);
-		}
-	} while(pstr < pstr_end);
+        WordIterator wordItBegin(val, val + strlen(val));
+        WordIterator wordItEnd;
+        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atoi(match); });
+    }
 }
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector<float>& pValue)
 {
-    std::list<float> tlist;
-
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
-	// and copy to array
-	if(tlist.size() > 0)
-	{
-		pValue.reserve(tlist.size());
-		for(std::list<float>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
-	}
-}
-
-void X3DImporter::XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list<double>& pValue)
-{
-    std::string str_fixed;
-
-	// at first check string values like '.xxx'.
-	ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed);
-	if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
-
-	// and convert all values and place it in list.
-	const char* pstr = str_fixed.c_str();
-	const char* pstr_end = pstr + str_fixed.size();
-
-	do
-	{
-		double tvald;
+    auto floatValue = std::dynamic_pointer_cast<const FIFloatValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (floatValue) {
+        pValue = floatValue->value;
+    }
+    else {
+        const char *val = mReader->getAttributeValue(pAttrIdx);
+        pValue.clear();
 
-		while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values.
+        //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws);
+        //const std::cregex_iterator wordItEnd;
+        //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stof(match.str()); });
 
-		if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces.
-		{
-			pstr = fast_atoreal_move(pstr, tvald, false);
-			pValue.push_back(tvald);
-		}
-	} while(pstr < pstr_end);
+        WordIterator wordItBegin(val, val + strlen(val));
+        WordIterator wordItEnd;
+        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atof(match); });
+    }
 }
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector<double>& pValue)
 {
-    std::list<double> tlist;
+    auto doubleValue = std::dynamic_pointer_cast<const FIDoubleValue>(mReader->getAttributeEncodedValue(pAttrIdx));
+    if (doubleValue) {
+        pValue = doubleValue->value;
+    }
+    else {
+        const char *val = mReader->getAttributeValue(pAttrIdx);
+        pValue.clear();
 
-	XML_ReadNode_GetAttrVal_AsListD(pAttrIdx, tlist);// read as list
-	// and copy to array
-	if(tlist.size() > 0)
-	{
-		pValue.reserve(tlist.size());
-		for(std::list<double>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
-	}
+        //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws);
+        //const std::cregex_iterator wordItEnd;
+        //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stod(match.str()); });
+
+        WordIterator wordItBegin(val, val + strlen(val));
+        WordIterator wordItEnd;
+        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atof(match); });
+    }
 }
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list<aiColor3D>& pValue)
 {
-    std::list<float> tlist;
+    std::vector<float> tlist;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list
 	if(tlist.size() % 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
 
 	// copy data to array
-	for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
+	for(std::vector<float>::iterator it = tlist.begin(); it != tlist.end();)
 	{
 		aiColor3D tcol;
 
@@ -635,13 +616,13 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::ve
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list<aiColor4D>& pValue)
 {
-    std::list<float> tlist;
+    std::vector<float> tlist;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list
 	if(tlist.size() % 4) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
 
 	// copy data to array
-	for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
+	for(std::vector<float>::iterator it = tlist.begin(); it != tlist.end();)
 	{
 		aiColor4D tcol;
 
@@ -671,16 +652,16 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::ve
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list<aiVector2D>& pValue)
 {
-    std::list<float> tlist;
+    std::vector<float> tlist;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list
     if ( tlist.size() % 2 )
     {
         Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) );
     }
 
 	// copy data to array
-	for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
+	for(std::vector<float>::iterator it = tlist.begin(); it != tlist.end();)
 	{
 		aiVector2D tvec;
 
@@ -708,16 +689,16 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::ve
 
 void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list<aiVector3D>& pValue)
 {
-    std::list<float> tlist;
+    std::vector<float> tlist;
 
-	XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
+	XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list
     if ( tlist.size() % 3 )
     {
         Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) );
     }
 
 	// copy data to array
-	for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
+	for(std::vector<float>::iterator it = tlist.begin(); it != tlist.end();)
 	{
 		aiVector3D tvec;
 
@@ -907,9 +888,9 @@ void X3DImporter::GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSi
 
 #undef MESH_RectParallelepiped_CREATE_VERT
 
-void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const
+void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::vector<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const
 {
-    std::list<int32_t> f_data(pCoordIdx);
+    std::vector<int32_t> f_data(pCoordIdx);
     std::vector<unsigned int> inds;
     unsigned int prim_type = 0;
 
@@ -922,7 +903,7 @@ void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list<int32_t>&
 	pFaces.reserve(f_data.size() / 3);
 	inds.reserve(4);
     //PrintVectorSet("build. ci", pCoordIdx);
-	for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
+	for(std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
 	{
 		// when face is got count how many indices in it.
 		if(*it == (-1))
@@ -1014,7 +995,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor4D
 	}// if(pColorPerVertex) else
 }
 
-void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
+void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
 										const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const
 {
     std::list<aiColor4D> tcol;
@@ -1029,7 +1010,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>&
 	MeshGeometry_AddColor(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
 }
 
-void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
+void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
 										const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const
 {
     std::vector<aiColor4D> col_tgt_arr;
@@ -1060,7 +1041,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>&
 			}
 			// create list with colors for every vertex.
 			col_tgt_arr.resize(pMesh.mNumVertices);
-			for(std::list<int32_t>::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++)
+			for(std::vector<int32_t>::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++)
 			{
                 if ( *colidx_it == ( -1 ) )
                 {
@@ -1108,7 +1089,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>&
 			// create list with colors for every vertex using faces indices.
 			col_tgt_arr.resize(pMesh.mNumFaces);
 
-			std::list<int32_t>::const_iterator colidx_it = pColorIdx.begin();
+			std::vector<int32_t>::const_iterator colidx_it = pColorIdx.begin();
 			for(size_t fi = 0; fi < pMesh.mNumFaces; fi++)
 			{
 				if((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
@@ -1138,7 +1119,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>&
 	MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex);
 }
 
-void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pNormalIdx,
+void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pNormalIdx,
 								const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const
 {
     std::vector<size_t> tind;
@@ -1153,35 +1134,36 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<int32_t>
 
 	if(pNormalPerVertex)
 	{
-		const std::list<int32_t>* srcidx;
-
 		if(pNormalIdx.size() > 0)
 		{
 			// check indices array count.
 			if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
 
-			srcidx = &pNormalIdx;
-		}
-		else
-		{
-			srcidx = &pCoordIdx;
-		}
+			tind.reserve(pNormalIdx.size());
+			for(std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); it++)
+			{
+				if(*it != (-1)) tind.push_back(*it);
+			}
 
-		tind.reserve(srcidx->size());
-		for(std::list<int32_t>::const_iterator it = srcidx->begin(); it != srcidx->end(); it++)
-		{
-			if(*it != (-1)) tind.push_back(*it);
-		}
+			// copy normals to mesh
+			pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
+			for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++)
+			{
+				if(tind[i] >= norm_arr_copy.size())
+					throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) +
+											") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + ".");
 
-		// copy normals to mesh
-		pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
-		for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++)
+				pMesh.mNormals[i] = norm_arr_copy[tind[i]];
+			}
+		}
+		else
 		{
-			if(tind[i] >= norm_arr_copy.size())
-				throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) +
-										") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + ".");
+			if(pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
 
-			pMesh.mNormals[i] = norm_arr_copy[tind[i]];
+			// copy normals to mesh
+			pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
+			std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
+			for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mNormals[i] = *norm_it++;
 		}
 	}// if(pNormalPerVertex)
 	else
@@ -1190,7 +1172,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<int32_t>
 		{
 			if(pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
 
-			std::list<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
+			std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
 
 			tind.reserve(pNormalIdx.size());
 			for(size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++) tind.push_back(*normidx_it++);
@@ -1243,7 +1225,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<aiVector
 	}// if(pNormalPerVertex) else
 }
 
-void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pTexCoordIdx,
+void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pTexCoordIdx,
 								const std::list<aiVector2D>& pTexCoords) const
 {
     std::vector<aiVector3D> texcoord_arr_copy;
@@ -1316,7 +1298,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<aiVect
     }
 }
 
-aiMesh* X3DImporter::GeometryHelper_MakeMesh(const std::list<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const
+aiMesh* X3DImporter::GeometryHelper_MakeMesh(const std::vector<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const
 {
     std::vector<aiFace> faces;
     unsigned int prim_type = 0;
@@ -1419,9 +1401,12 @@ void X3DImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::s
 	}
 }
 
+extern FIVocabulary X3D_vocabulary_3_2;
+extern FIVocabulary X3D_vocabulary_3_3;
+
 void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
 {
-    irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
+    std::unique_ptr<FIReader> OldReader = std::move(mReader);// store current XMLreader.
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
 
 	// Check whether we can read from the file
@@ -1429,19 +1414,18 @@ void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
     {
         throw DeadlyImportError( "Failed to open X3D file " + pFile + "." );
     }
-	// generate a XML reader for it
-	std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
-	mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
+	mReader = FIReader::create(file.get());
     if ( !mReader )
     {
         throw DeadlyImportError( "Failed to create XML reader for file" + pFile + "." );
     }
+    mReader->registerVocabulary("urn:web3d:x3d:fi-vocabulary-3.2", &X3D_vocabulary_3_2);
+    mReader->registerVocabulary("urn:web3d:x3d:fi-vocabulary-3.3", &X3D_vocabulary_3_3);
 	// start reading
 	ParseNode_Root();
 
-	delete mReader;
 	// restore old XMLreader
-	mReader = OldReader;
+	mReader = std::move(OldReader);
 }
 
 void X3DImporter::ParseNode_Root()
@@ -1655,7 +1639,7 @@ bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool p
 {
     const std::string extension = GetExtension(pFile);
 
-	if(extension == "x3d") return true;
+	if((extension == "x3d") || (extension == "x3db")) return true;
 
 	if(!extension.length() || pCheckSig)
 	{
@@ -1670,6 +1654,7 @@ bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool p
 void X3DImporter::GetExtensionList(std::set<std::string>& pExtensionList)
 {
 	pExtensionList.insert("x3d");
+	pExtensionList.insert("x3db");
 }
 
 const aiImporterDesc* X3DImporter::GetInfo () const
@@ -1679,9 +1664,13 @@ const aiImporterDesc* X3DImporter::GetInfo () const
 
 void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
 {
+	mpIOHandler = pIOHandler;
+
 	Clear();// delete old graph.
-	mFileDir = DefaultIOSystem::absolutePath(pFile);
+	std::string::size_type slashPos = pFile.find_last_of("\\/");
+	pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
 	ParseFile(pFile, pIOHandler);
+	pIOHandler->PopDirectory();
 	//
 	// Assimp use static arrays of objects for fast speed of rendering. That's good, but need some additional operations/
 	// We know that geometry objects(meshes) are stored in <Shape>, also in <Shape>-><Appearance> materials(in Assimp logical view)

+ 14 - 21
code/X3DImporter.hpp

@@ -56,6 +56,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/types.h>
 #include "BaseImporter.h"
 #include "irrXMLWrapper.h"
+#include "FIReader.hpp"
+//#include <regex>
 
 namespace Assimp {
 
@@ -101,7 +103,7 @@ namespace Assimp {
 ///		Navigation component:
 ///			"Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup"
 ///		Networking component:
-///			"Anchor", "LoadSensor"
+///			"EXPORT", "IMPORT", "Anchor", "LoadSensor"
 ///		NURBS component:
 ///			"Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
 ///			"NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
@@ -449,33 +451,21 @@ private:
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \param [out] pValue - read data.
-	void XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list<bool>& pValue);
-
-	/// \overload void XML_ReadNode_GetAttrVal_AsListBool(const int pAttrIdx, std::list<bool>& pValue)
 	void XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector<bool>& pValue);
 
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \param [out] pValue - read data.
-	void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list<int32_t>& pValue);
-
-	/// \overload void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list<int32_t>& pValue)
 	void XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector<int32_t>& pValue);
 
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \param [out] pValue - read data.
-	void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list<float>& pValue);
-
-    /// \overload void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list<float>& pValue)
 	void XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector<float>& pValue);
 
     /// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \param [out] pValue - read data.
-	void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list<double>& pValue);
-
-	/// \overload void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list<double>& pValue)
 	void XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector<double>& pValue);
 
 	/// Read attribute value.
@@ -554,7 +544,7 @@ private:
 	/// \param [in] pCoordIdx - vertices indices divided by delimiter "-1".
 	/// \param [in] pFaces - created faces array.
 	/// \param [in] pPrimitiveTypes - type of primitives in faces.
-	void GeometryHelper_CoordIdxStr2FacesArr(const std::list<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const;
+	void GeometryHelper_CoordIdxStr2FacesArr(const std::vector<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const;
 
 	/// Add colors to mesh.
 	/// a. If colorPerVertex is FALSE, colours are applied to each face, as follows:
@@ -573,11 +563,11 @@ private:
 	/// then pColorIdx contain color indices for every faces and must not contain delimiter "-1".
 	/// \param [in] pColors - defined colors.
 	/// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face.
-	void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
+	void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
 								const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const;
 
 	/// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx, const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const;
-	void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
+	void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
 								const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const;
 
 	/// Add colors to mesh.
@@ -590,14 +580,14 @@ private:
 	void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const;
 
 	/// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor;
-	void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pNormalIdx,
+	void MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pNormalIdx,
 								const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const;
 
 	/// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor;
 	void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const;
 
     /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor;
-	void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pTexCoordIdx,
+	void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pTexCoordIdx,
 								const std::list<aiVector2D>& pTexCoords) const;
 
     /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor;
@@ -607,7 +597,7 @@ private:
 	/// \param [in] pCoordIdx - vertices indices divided by delimiter "-1".
 	/// \param [in] pVertices - vertices of mesh.
 	/// \return created mesh.
-	aiMesh* GeometryHelper_MakeMesh(const std::list<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const;
+	aiMesh* GeometryHelper_MakeMesh(const std::vector<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const;
 
 	/***********************************************/
 	/******** Functions: parse set private *********/
@@ -826,13 +816,16 @@ private:
     /****************** Constants ******************/
     /***********************************************/
     static const aiImporterDesc Description;
+    //static const std::regex pattern_nws;
+    //static const std::regex pattern_true;
+
 
     /***********************************************/
     /****************** Variables ******************/
     /***********************************************/
     CX3DImporter_NodeElement* NodeElement_Cur;///< Current element.
-    irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
-    std::string mFileDir;
+    std::unique_ptr<FIReader> mReader;///< Pointer to XML-reader object
+    IOSystem *mpIOHandler;
 };// class X3DImporter
 
 }// namespace Assimp

+ 11 - 11
code/X3DImporter_Geometry3D.cpp

@@ -285,7 +285,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid()
     bool ccw = true;
     bool colorPerVertex = true;
     float creaseAngle = 0;
-    std::list<float> height;
+    std::vector<float> height;
     bool normalPerVertex = true;
     bool solid = true;
     int32_t xDimension = 0;
@@ -301,7 +301,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid()
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat);
-		MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsListF);
+		MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsArrF);
 		MACRO_ATTRREAD_CHECK_RET("xDimension", xDimension, XML_ReadNode_GetAttrVal_AsI32);
 		MACRO_ATTRREAD_CHECK_RET("xSpacing", xSpacing, XML_ReadNode_GetAttrVal_AsFloat);
 		MACRO_ATTRREAD_CHECK_RET("zDimension", zDimension, XML_ReadNode_GetAttrVal_AsI32);
@@ -326,7 +326,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid()
 		CX3DImporter_NodeElement_ElevationGrid& grid_alias = *((CX3DImporter_NodeElement_ElevationGrid*)ne);// create alias for conveience
 
 		{// create grid vertices list
-			std::list<float>::const_iterator he_it = height.begin();
+			std::vector<float>::const_iterator he_it = height.begin();
 
 			for(int32_t zi = 0; zi < zDimension; zi++)// rows
 			{
@@ -863,29 +863,29 @@ void X3DImporter::ParseNode_Geometry3D_IndexedFaceSet()
 {
     std::string use, def;
     bool ccw = true;
-    std::list<int32_t> colorIndex;
+    std::vector<int32_t> colorIndex;
     bool colorPerVertex = true;
     bool convex = true;
-    std::list<int32_t> coordIndex;
+    std::vector<int32_t> coordIndex;
     float creaseAngle = 0;
-    std::list<int32_t> normalIndex;
+    std::vector<int32_t> normalIndex;
     bool normalPerVertex = true;
     bool solid = true;
-    std::list<int32_t> texCoordIndex;
+    std::vector<int32_t> texCoordIndex;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat);
-		MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 	MACRO_ATTRREAD_LOOPEND;
 
 	// if "USE" defined then find already defined element.

+ 8 - 8
code/X3DImporter_Metadata.cpp

@@ -123,14 +123,14 @@ void X3DImporter::ParseNode_MetadataBoolean()
 {
     std::string def, use;
     std::string name, reference;
-    std::list<bool> value;
+    std::vector<bool> value;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
 		MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListB);
+		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrB);
 	MACRO_ATTRREAD_LOOPEND;
 
 	MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaBoolean, "MetadataBoolean", ENET_MetaBoolean);
@@ -147,14 +147,14 @@ void X3DImporter::ParseNode_MetadataDouble()
 {
     std::string def, use;
     std::string name, reference;
-    std::list<double> value;
+    std::vector<double> value;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
 		MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListD);
+		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrD);
 	MACRO_ATTRREAD_LOOPEND;
 
 	MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaDouble, "MetadataDouble", ENET_MetaDouble);
@@ -171,14 +171,14 @@ void X3DImporter::ParseNode_MetadataFloat()
 {
     std::string def, use;
     std::string name, reference;
-    std::list<float> value;
+    std::vector<float> value;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
 		MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListF);
+		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrF);
 	MACRO_ATTRREAD_LOOPEND;
 
 	MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaFloat, "MetadataFloat", ENET_MetaFloat);
@@ -195,14 +195,14 @@ void X3DImporter::ParseNode_MetadataInteger()
 {
     std::string def, use;
     std::string name, reference;
-    std::list<int32_t> value;
+    std::vector<int32_t> value;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
 		MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrI32);
 	MACRO_ATTRREAD_LOOPEND;
 
 	MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaInteger, "MetadataInteger", ENET_MetaInteger);

+ 28 - 5
code/X3DImporter_Networking.cpp

@@ -51,9 +51,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // Header files, Assimp.
 #include <assimp/DefaultIOSystem.h>
 
+//#include <regex>
+
 namespace Assimp
 {
 
+//static std::regex pattern_parentDir(R"((^|/)[^/]+/../)");
+static std::string parentDir("/../");
+
 // <Inline
 // DEF=""              ID
 // USE=""              IDREF
@@ -89,12 +94,30 @@ void X3DImporter::ParseNode_Networking_Inline()
 
 		if(load && (url.size() > 0))
 		{
-			DefaultIOSystem io_handler;
-			std::string full_path;
-
-			full_path = mFileDir + "/" + url.front();
+			std::string full_path = mpIOHandler->CurrentDirectory() + url.front();
+
+			//full_path = std::regex_replace(full_path, pattern_parentDir, "$1");
+			for (std::string::size_type pos = full_path.find(parentDir); pos != std::string::npos; pos = full_path.find(parentDir, pos)) {
+				if (pos > 0) {
+					std::string::size_type pos2 = full_path.rfind('/', pos - 1);
+					if (pos2 != std::string::npos) {
+						full_path.erase(pos2, pos - pos2 + 3);
+						pos = pos2;
+					}
+					else {
+						full_path.erase(0, pos + 4);
+						pos = 0;
+					}
+				}
+				else {
+					pos += 3;
+				}
+			}
 			// Attribute "url" can contain list of strings. But we need only one - first.
-			ParseFile(full_path, &io_handler);
+			std::string::size_type slashPos = full_path.find_last_of("\\/");
+			mpIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : full_path.substr(0, slashPos + 1));
+			ParseFile(full_path, mpIOHandler);
+			mpIOHandler->PopDirectory();
 		}
 
 		// check for X3DMetadataObject childs.

+ 14 - 13
code/X3DImporter_Node.hpp

@@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Header files, stdlib.
 #include <list>
+#include <vector>
 #include <string>
 
 /// \class CX3DImporter_NodeElement
@@ -264,7 +265,7 @@ public:
 /// This struct describe metavalue of type boolean.
 struct CX3DImporter_NodeElement_MetaBoolean : public CX3DImporter_NodeElement_Meta
 {
-	std::list<bool> Value;///< Stored value.
+	std::vector<bool> Value;///< Stored value.
 
 	/// \fn CX3DImporter_NodeElement_MetaBoolean(CX3DImporter_NodeElement* pParent)
 	/// Constructor
@@ -279,7 +280,7 @@ struct CX3DImporter_NodeElement_MetaBoolean : public CX3DImporter_NodeElement_Me
 /// This struct describe metavalue of type double.
 struct CX3DImporter_NodeElement_MetaDouble : public CX3DImporter_NodeElement_Meta
 {
-	std::list<double> Value;///< Stored value.
+	std::vector<double> Value;///< Stored value.
 
 	/// \fn CX3DImporter_NodeElement_MetaDouble(CX3DImporter_NodeElement* pParent)
 	/// Constructor
@@ -294,7 +295,7 @@ struct CX3DImporter_NodeElement_MetaDouble : public CX3DImporter_NodeElement_Met
 /// This struct describe metavalue of type float.
 struct CX3DImporter_NodeElement_MetaFloat : public CX3DImporter_NodeElement_Meta
 {
-	std::list<float> Value;///< Stored value.
+	std::vector<float> Value;///< Stored value.
 
 	/// \fn CX3DImporter_NodeElement_MetaFloat(CX3DImporter_NodeElement* pParent)
 	/// Constructor
@@ -309,7 +310,7 @@ struct CX3DImporter_NodeElement_MetaFloat : public CX3DImporter_NodeElement_Meta
 /// This struct describe metavalue of type integer.
 struct CX3DImporter_NodeElement_MetaInteger : public CX3DImporter_NodeElement_Meta
 {
-	std::list<int32_t> Value;///< Stored value.
+	std::vector<int32_t> Value;///< Stored value.
 
 	/// \fn CX3DImporter_NodeElement_MetaInteger(CX3DImporter_NodeElement* pParent)
 	/// Constructor
@@ -508,7 +509,7 @@ public:
 	/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
 	/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
 	float CreaseAngle;
-	std::list<int32_t> CoordIdx;///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces.
+	std::vector<int32_t> CoordIdx;///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces.
 
 	/***********************************************/
 	/****************** Functions ******************/
@@ -554,21 +555,21 @@ public:
 	/// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the
 	/// ccw field, results are undefined.
 	bool CCW;
-	std::list<int32_t> ColorIndex;///< Field to specify the polygonal faces by indexing into the <Color> or <ColorRGBA>.
+	std::vector<int32_t> ColorIndex;///< Field to specify the polygonal faces by indexing into the <Color> or <ColorRGBA>.
 	bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line).
 	/// \var Convex
 	/// The convex field indicates whether all polygons in the shape are convex (TRUE). A polygon is convex if it is planar, does not intersect itself,
 	/// and all of the interior angles at its vertices are less than 180 degrees. Non planar and self intersecting polygons may produce undefined results
 	/// even if the convex field is FALSE.
 	bool Convex;
-	std::list<int32_t> CoordIndex;///< Field to specify the polygonal faces by indexing into the <Coordinate>.
+	std::vector<int32_t> CoordIndex;///< Field to specify the polygonal faces by indexing into the <Coordinate>.
 	/// \var CreaseAngle
 	/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
 	/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
 	float CreaseAngle;
-	std::list<int32_t> NormalIndex;///< Field to specify the polygonal faces by indexing into the <Normal>.
+	std::vector<int32_t> NormalIndex;///< Field to specify the polygonal faces by indexing into the <Normal>.
 	bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line).
-	std::list<int32_t> TexCoordIndex;///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
+	std::vector<int32_t> TexCoordIndex;///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
 
 	/***********************************************/
 	/****************** Functions ******************/
@@ -616,10 +617,10 @@ public:
 	bool CCW;
 	bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line).
 	bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line).
-	std::list<int32_t> CoordIndex;///< Field to specify the polygonal faces by indexing into the <Coordinate>.
-	std::list<int32_t> NormalIndex;///< Field to specify the polygonal faces by indexing into the <Normal>.
-	std::list<int32_t> TexCoordIndex;///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
-	std::list<int32_t> VertexCount;///< Field describes how many vertices are to be used in each polyline(polygon) from the <Coordinate> field.
+	std::vector<int32_t> CoordIndex;///< Field to specify the polygonal faces by indexing into the <Coordinate>.
+	std::vector<int32_t> NormalIndex;///< Field to specify the polygonal faces by indexing into the <Normal>.
+	std::vector<int32_t> TexCoordIndex;///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
+	std::vector<int32_t> VertexCount;///< Field describes how many vertices are to be used in each polyline(polygon) from the <Coordinate> field.
 
 	/***********************************************/
 	/****************** Functions ******************/

+ 117 - 22
code/X3DImporter_Rendering.cpp

@@ -180,16 +180,16 @@ void X3DImporter::ParseNode_Rendering_Coordinate()
 void X3DImporter::ParseNode_Rendering_IndexedLineSet()
 {
     std::string use, def;
-    std::list<int32_t> colorIndex;
+    std::vector<int32_t> colorIndex;
     bool colorPerVertex = true;
-    std::list<int32_t> coordIndex;
+    std::vector<int32_t> coordIndex;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
-		MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsArrI32);
 	MACRO_ATTRREAD_LOOPEND;
 
 	// if "USE" defined then find already defined element.
@@ -256,7 +256,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet()
     std::string use, def;
     bool ccw = true;
     bool colorPerVertex = true;
-    std::list<int32_t> index;
+    std::vector<int32_t> index;
     bool normalPerVertex = true;
     bool solid = true;
     CX3DImporter_NodeElement* ne( nullptr );
@@ -265,7 +265,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet()
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
 	MACRO_ATTRREAD_LOOPEND;
@@ -288,9 +288,46 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet()
 
 		ne_alias.CCW = ccw;
 		ne_alias.ColorPerVertex = colorPerVertex;
-		ne_alias.CoordIndex = index;
 		ne_alias.NormalPerVertex = normalPerVertex;
 		ne_alias.Solid = solid;
+
+		ne_alias.CoordIndex.clear();
+		int counter = 0;
+		int32_t idx[3];
+		for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++)
+		{
+			idx[2] = *idx_it;
+			if (idx[2] < 0)
+			{
+				counter = 0;
+			}
+			else
+			{
+				if (counter >= 2)
+				{
+					if(ccw)
+					{
+						ne_alias.CoordIndex.push_back(idx[0]);
+						ne_alias.CoordIndex.push_back(idx[1]);
+						ne_alias.CoordIndex.push_back(idx[2]);
+					}
+					else
+					{
+						ne_alias.CoordIndex.push_back(idx[0]);
+						ne_alias.CoordIndex.push_back(idx[2]);
+						ne_alias.CoordIndex.push_back(idx[1]);
+					}
+					ne_alias.CoordIndex.push_back(-1);
+					idx[1] = idx[2];
+				}
+				else
+				{
+					idx[counter] = idx[2];
+				}
+				++counter;
+			}
+		}// for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
+
         // check for child nodes
         if(!mReader->isEmptyElement())
         {
@@ -337,7 +374,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet()
     std::string use, def;
     bool ccw = true;
     bool colorPerVertex = true;
-    std::list<int32_t> index;
+    std::vector<int32_t> index;
     bool normalPerVertex = true;
     bool solid = true;
     CX3DImporter_NodeElement* ne( nullptr );
@@ -346,7 +383,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet()
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
 	MACRO_ATTRREAD_LOOPEND;
@@ -369,9 +406,34 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet()
 
 		ne_alias.CCW = ccw;
 		ne_alias.ColorPerVertex = colorPerVertex;
-		ne_alias.CoordIndex = index;
 		ne_alias.NormalPerVertex = normalPerVertex;
 		ne_alias.Solid = solid;
+
+		ne_alias.CoordIndex.clear();
+		int counter = 0;
+		int32_t idx[3];
+		for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++)
+		{
+			idx[counter++] = *idx_it;
+			if (counter > 2)
+			{
+				counter = 0;
+				if(ccw)
+				{
+					ne_alias.CoordIndex.push_back(idx[0]);
+					ne_alias.CoordIndex.push_back(idx[1]);
+					ne_alias.CoordIndex.push_back(idx[2]);
+				}
+				else
+				{
+					ne_alias.CoordIndex.push_back(idx[0]);
+					ne_alias.CoordIndex.push_back(idx[2]);
+					ne_alias.CoordIndex.push_back(idx[1]);
+				}
+				ne_alias.CoordIndex.push_back(-1);
+			}
+		}// for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
+
         // check for child nodes
         if(!mReader->isEmptyElement())
         {
@@ -418,7 +480,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet()
     std::string use, def;
     bool ccw = true;
     bool colorPerVertex = true;
-    std::list<int32_t> index;
+    std::vector<int32_t> index;
     bool normalPerVertex = true;
     bool solid = true;
     CX3DImporter_NodeElement* ne( nullptr );
@@ -427,7 +489,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet()
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
 	MACRO_ATTRREAD_LOOPEND;
@@ -450,9 +512,42 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet()
 
 		ne_alias.CCW = ccw;
 		ne_alias.ColorPerVertex = colorPerVertex;
-		ne_alias.CoordIndex = index;
 		ne_alias.NormalPerVertex = normalPerVertex;
 		ne_alias.Solid = solid;
+
+		ne_alias.CoordIndex.clear();
+		int counter = 0;
+		int32_t idx[3];
+		for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++)
+		{
+			idx[2] = *idx_it;
+			if (idx[2] < 0)
+			{
+				counter = 0;
+			}
+			else
+			{
+				if (counter >= 2)
+				{
+					if(ccw)
+					{
+						ne_alias.CoordIndex.push_back(idx[0]);
+						ne_alias.CoordIndex.push_back(idx[1]);
+						ne_alias.CoordIndex.push_back(idx[2]);
+					}
+					else
+					{
+						ne_alias.CoordIndex.push_back(idx[0]);
+						ne_alias.CoordIndex.push_back(idx[2]);
+						ne_alias.CoordIndex.push_back(idx[1]);
+					}
+					ne_alias.CoordIndex.push_back(-1);
+				}
+				idx[counter & 1] = idx[2];
+				++counter;
+			}
+		}// for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
+
         // check for child nodes
         if(!mReader->isEmptyElement())
         {
@@ -492,12 +587,12 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet()
 void X3DImporter::ParseNode_Rendering_LineSet()
 {
     std::string use, def;
-    std::list<int32_t> vertexCount;
+    std::vector<int32_t> vertexCount;
     CX3DImporter_NodeElement* ne( nullptr );
 
 	MACRO_ATTRREAD_LOOPBEG;
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
-		MACRO_ATTRREAD_CHECK_REF("vertexCount", vertexCount, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("vertexCount", vertexCount, XML_ReadNode_GetAttrVal_AsArrI32);
 	MACRO_ATTRREAD_LOOPEND;
 
 	// if "USE" defined then find already defined element.
@@ -521,7 +616,7 @@ void X3DImporter::ParseNode_Rendering_LineSet()
 		size_t coord_num = 0;
 
 		ne_alias.CoordIndex.clear();
-		for(std::list<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
+		for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
 		{
 			if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two.");
 
@@ -627,7 +722,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet()
     std::string use, def;
     bool ccw = true;
     bool colorPerVertex = true;
-    std::list<int32_t> fanCount;
+    std::vector<int32_t> fanCount;
     bool normalPerVertex = true;
     bool solid = true;
     CX3DImporter_NodeElement* ne( nullptr );
@@ -636,7 +731,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet()
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("fanCount", fanCount, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("fanCount", fanCount, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
 	MACRO_ATTRREAD_LOOPEND;
@@ -669,7 +764,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet()
 		// assign indices for first triangle
 		coord_num_first = 0;
 		coord_num_prev = 1;
-		for(std::list<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
+		for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
 		{
 			if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three.");
 
@@ -818,7 +913,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet()
     std::string use, def;
     bool ccw = true;
     bool colorPerVertex = true;
-    std::list<int32_t> stripCount;
+    std::vector<int32_t> stripCount;
     bool normalPerVertex = true;
     bool solid = true;
     CX3DImporter_NodeElement* ne( nullptr );
@@ -827,7 +922,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet()
 		MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
 		MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
-		MACRO_ATTRREAD_CHECK_REF("stripCount", stripCount, XML_ReadNode_GetAttrVal_AsListI32);
+		MACRO_ATTRREAD_CHECK_REF("stripCount", stripCount, XML_ReadNode_GetAttrVal_AsArrI32);
 		MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
 		MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
 	MACRO_ATTRREAD_LOOPEND;
@@ -860,7 +955,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet()
 
 		ne_alias.CoordIndex.clear();
 		coord_num_sb = 0;
-		for(std::list<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
+		for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
 		{
 			if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three.");
 

+ 1675 - 0
code/X3DVocabulary.cpp

@@ -0,0 +1,1675 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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   X3DVocabulary.cpp
+/// \brief  Vocabulary for Fast Infoset encoded binary X3D files.
+/// \date   2017
+/// \author Patrick Daehne
+
+#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
+#include "FIReader.hpp"
+
+namespace Assimp {
+
+static const char *encodingAlgorithmTable_3_2[] = {
+    "encoder://web3d.org/QuantizedFloatArrayEncoder",
+    "encoder://web3d.org/DeltazlibIntArrayEncoder",
+    "encoder://web3d.org/QuantizedzlibFloatArrayEncoder",
+    "encoder://web3d.org/zlibFloatArrayEncoder",
+    "encoder://web3d.org/QuantizedDoubleArrayEncoder",
+    "encoder://web3d.org/zlibDoubleArrayEncoder",
+    "encoder://web3d.org/QuantizedzlibDoubleArrayEncoder",
+    "encoder://web3d.org/RangeIntArrayEncoder"
+};
+
+static const std::shared_ptr<const FIValue> attributeValueTable_3_2[] = {
+    FIStringValue::create("false"),
+    FIStringValue::create("true")
+};
+
+static const FIQName elementNameTable_3_2[] = {
+    { "Shape", nullptr, nullptr },
+    { "Appearance", nullptr, nullptr },
+    { "Material", nullptr, nullptr },
+    { "IndexedFaceSet", nullptr, nullptr },
+    { "ProtoInstance", nullptr, nullptr },
+    { "Transform", nullptr, nullptr },
+    { "ImageTexture", nullptr, nullptr },
+    { "TextureTransform", nullptr, nullptr },
+    { "Coordinate", nullptr, nullptr },
+    { "Normal", nullptr, nullptr },
+    { "Color", nullptr, nullptr },
+    { "ColorRGBA", nullptr, nullptr },
+    { "TextureCoordinate", nullptr, nullptr },
+    { "ROUTE", nullptr, nullptr },
+    { "fieldValue", nullptr, nullptr },
+    { "Group", nullptr, nullptr },
+    { "LOD", nullptr, nullptr },
+    { "Switch", nullptr, nullptr },
+    { "Script", nullptr, nullptr },
+    { "IndexedTriangleFanSet", nullptr, nullptr },
+    { "IndexedTriangleSet", nullptr, nullptr },
+    { "IndexedTriangleStripSet", nullptr, nullptr },
+    { "MultiTexture", nullptr, nullptr },
+    { "MultiTextureCoordinate", nullptr, nullptr },
+    { "MultiTextureTransform", nullptr, nullptr },
+    { "IndexedLineSet", nullptr, nullptr },
+    { "PointSet", nullptr, nullptr },
+    { "StaticGroup", nullptr, nullptr },
+    { "Sphere", nullptr, nullptr },
+    { "Box", nullptr, nullptr },
+    { "Cone", nullptr, nullptr },
+    { "Anchor", nullptr, nullptr },
+    { "Arc2D", nullptr, nullptr },
+    { "ArcClose2D", nullptr, nullptr },
+    { "AudioClip", nullptr, nullptr },
+    { "Background", nullptr, nullptr },
+    { "Billboard", nullptr, nullptr },
+    { "BooleanFilter", nullptr, nullptr },
+    { "BooleanSequencer", nullptr, nullptr },
+    { "BooleanToggle", nullptr, nullptr },
+    { "BooleanTrigger", nullptr, nullptr },
+    { "Circle2D", nullptr, nullptr },
+    { "Collision", nullptr, nullptr },
+    { "ColorInterpolator", nullptr, nullptr },
+    { "Contour2D", nullptr, nullptr },
+    { "ContourPolyline2D", nullptr, nullptr },
+    { "CoordinateDouble", nullptr, nullptr },
+    { "CoordinateInterpolator", nullptr, nullptr },
+    { "CoordinateInterpolator2D", nullptr, nullptr },
+    { "Cylinder", nullptr, nullptr },
+    { "CylinderSensor", nullptr, nullptr },
+    { "DirectionalLight", nullptr, nullptr },
+    { "Disk2D", nullptr, nullptr },
+    { "EXPORT", nullptr, nullptr },
+    { "ElevationGrid", nullptr, nullptr },
+    { "EspduTransform", nullptr, nullptr },
+    { "ExternProtoDeclare", nullptr, nullptr },
+    { "Extrusion", nullptr, nullptr },
+    { "FillProperties", nullptr, nullptr },
+    { "Fog", nullptr, nullptr },
+    { "FontStyle", nullptr, nullptr },
+    { "GeoCoordinate", nullptr, nullptr },
+    { "GeoElevationGrid", nullptr, nullptr },
+    { "GeoLOD", nullptr, nullptr },
+    { "GeoLocation", nullptr, nullptr },
+    { "GeoMetadata", nullptr, nullptr },
+    { "GeoOrigin", nullptr, nullptr },
+    { "GeoPositionInterpolator", nullptr, nullptr },
+    { "GeoTouchSensor", nullptr, nullptr },
+    { "GeoViewpoint", nullptr, nullptr },
+    { "HAnimDisplacer", nullptr, nullptr },
+    { "HAnimHumanoid", nullptr, nullptr },
+    { "HAnimJoint", nullptr, nullptr },
+    { "HAnimSegment", nullptr, nullptr },
+    { "HAnimSite", nullptr, nullptr },
+    { "IMPORT", nullptr, nullptr },
+    { "IS", nullptr, nullptr },
+    { "Inline", nullptr, nullptr },
+    { "IntegerSequencer", nullptr, nullptr },
+    { "IntegerTrigger", nullptr, nullptr },
+    { "KeySensor", nullptr, nullptr },
+    { "LineProperties", nullptr, nullptr },
+    { "LineSet", nullptr, nullptr },
+    { "LoadSensor", nullptr, nullptr },
+    { "MetadataDouble", nullptr, nullptr },
+    { "MetadataFloat", nullptr, nullptr },
+    { "MetadataInteger", nullptr, nullptr },
+    { "MetadataSet", nullptr, nullptr },
+    { "MetadataString", nullptr, nullptr },
+    { "MovieTexture", nullptr, nullptr },
+    { "NavigationInfo", nullptr, nullptr },
+    { "NormalInterpolator", nullptr, nullptr },
+    { "NurbsCurve", nullptr, nullptr },
+    { "NurbsCurve2D", nullptr, nullptr },
+    { "NurbsOrientationInterpolator", nullptr, nullptr },
+    { "NurbsPatchSurface", nullptr, nullptr },
+    { "NurbsPositionInterpolator", nullptr, nullptr },
+    { "NurbsSet", nullptr, nullptr },
+    { "NurbsSurfaceInterpolator", nullptr, nullptr },
+    { "NurbsSweptSurface", nullptr, nullptr },
+    { "NurbsSwungSurface", nullptr, nullptr },
+    { "NurbsTextureCoordinate", nullptr, nullptr },
+    { "NurbsTrimmedSurface", nullptr, nullptr },
+    { "OrientationInterpolator", nullptr, nullptr },
+    { "PixelTexture", nullptr, nullptr },
+    { "PlaneSensor", nullptr, nullptr },
+    { "PointLight", nullptr, nullptr },
+    { "Polyline2D", nullptr, nullptr },
+    { "Polypoint2D", nullptr, nullptr },
+    { "PositionInterpolator", nullptr, nullptr },
+    { "PositionInterpolator2D", nullptr, nullptr },
+    { "ProtoBody", nullptr, nullptr },
+    { "ProtoDeclare", nullptr, nullptr },
+    { "ProtoInterface", nullptr, nullptr },
+    { "ProximitySensor", nullptr, nullptr },
+    { "ReceiverPdu", nullptr, nullptr },
+    { "Rectangle2D", nullptr, nullptr },
+    { "ScalarInterpolator", nullptr, nullptr },
+    { "Scene", nullptr, nullptr },
+    { "SignalPdu", nullptr, nullptr },
+    { "Sound", nullptr, nullptr },
+    { "SphereSensor", nullptr, nullptr },
+    { "SpotLight", nullptr, nullptr },
+    { "StringSensor", nullptr, nullptr },
+    { "Text", nullptr, nullptr },
+    { "TextureBackground", nullptr, nullptr },
+    { "TextureCoordinateGenerator", nullptr, nullptr },
+    { "TimeSensor", nullptr, nullptr },
+    { "TimeTrigger", nullptr, nullptr },
+    { "TouchSensor", nullptr, nullptr },
+    { "TransmitterPdu", nullptr, nullptr },
+    { "TriangleFanSet", nullptr, nullptr },
+    { "TriangleSet", nullptr, nullptr },
+    { "TriangleSet2D", nullptr, nullptr },
+    { "TriangleStripSet", nullptr, nullptr },
+    { "Viewpoint", nullptr, nullptr },
+    { "VisibilitySensor", nullptr, nullptr },
+    { "WorldInfo", nullptr, nullptr },
+    { "X3D", nullptr, nullptr },
+    { "component", nullptr, nullptr },
+    { "connect", nullptr, nullptr },
+    { "field", nullptr, nullptr },
+    { "head", nullptr, nullptr },
+    { "humanoidBodyType", nullptr, nullptr },
+    { "meta", nullptr, nullptr },
+    { "CADAssembly", nullptr, nullptr },
+    { "CADFace", nullptr, nullptr },
+    { "CADLayer", nullptr, nullptr },
+    { "CADPart", nullptr, nullptr },
+    { "ComposedCubeMapTexture", nullptr, nullptr },
+    { "ComposedShader", nullptr, nullptr },
+    { "ComposedTexture3D", nullptr, nullptr },
+    { "FloatVertexAttribute", nullptr, nullptr },
+    { "FogCoordinate", nullptr, nullptr },
+    { "GeneratedCubeMapTexture", nullptr, nullptr },
+    { "ImageCubeMapTexture", nullptr, nullptr },
+    { "ImageTexture3D", nullptr, nullptr },
+    { "IndexedQuadSet", nullptr, nullptr },
+    { "LocalFog", nullptr, nullptr },
+    { "Matrix3VertexAttribute", nullptr, nullptr },
+    { "Matrix4VertexAttribute", nullptr, nullptr },
+    { "PackagedShader", nullptr, nullptr },
+    { "PixelTexture3D", nullptr, nullptr },
+    { "ProgramShader", nullptr, nullptr },
+    { "QuadSet", nullptr, nullptr },
+    { "ShaderPart", nullptr, nullptr },
+    { "ShaderProgram", nullptr, nullptr },
+    { "TextureCoordinate3D", nullptr, nullptr },
+    { "TextureCoordinate4D", nullptr, nullptr },
+    { "TextureTransform3D", nullptr, nullptr },
+    { "TextureTransformMatrix3D", nullptr, nullptr },
+    { "BallJoint", nullptr, nullptr },
+    { "BoundedPhysicsModel", nullptr, nullptr },
+    { "ClipPlane", nullptr, nullptr },
+    { "CollidableOffset", nullptr, nullptr },
+    { "CollidableShape", nullptr, nullptr },
+    { "CollisionCollection", nullptr, nullptr },
+    { "CollisionSensor", nullptr, nullptr },
+    { "CollisionSpace", nullptr, nullptr },
+    { "ColorDamper", nullptr, nullptr },
+    { "ConeEmitter", nullptr, nullptr },
+    { "Contact", nullptr, nullptr },
+    { "CoordinateDamper", nullptr, nullptr },
+    { "DISEntityManager", nullptr, nullptr },
+    { "DISEntityTypeMapping", nullptr, nullptr },
+    { "DoubleAxisHingeJoint", nullptr, nullptr },
+    { "EaseInEaseOut", nullptr, nullptr },
+    { "ExplosionEmitter", nullptr, nullptr },
+    { "ForcePhysicsModel", nullptr, nullptr },
+    { "GeoProximitySensor", nullptr, nullptr },
+    { "GeoTransform", nullptr, nullptr },
+    { "Layer", nullptr, nullptr },
+    { "LayerSet", nullptr, nullptr },
+    { "Layout", nullptr, nullptr },
+    { "LayoutGroup", nullptr, nullptr },
+    { "LayoutLayer", nullptr, nullptr },
+    { "LinePickSensor", nullptr, nullptr },
+    { "MotorJoint", nullptr, nullptr },
+    { "OrientationChaser", nullptr, nullptr },
+    { "OrientationDamper", nullptr, nullptr },
+    { "OrthoViewpoint", nullptr, nullptr },
+    { "ParticleSystem", nullptr, nullptr },
+    { "PickableGroup", nullptr, nullptr },
+    { "PointEmitter", nullptr, nullptr },
+    { "PointPickSensor", nullptr, nullptr },
+    { "PolylineEmitter", nullptr, nullptr },
+    { "PositionChaser", nullptr, nullptr },
+    { "PositionChaser2D", nullptr, nullptr },
+    { "PositionDamper", nullptr, nullptr },
+    { "PositionDamper2D", nullptr, nullptr },
+    { "PrimitivePickSensor", nullptr, nullptr },
+    { "RigidBody", nullptr, nullptr },
+    { "RigidBodyCollection", nullptr, nullptr },
+    { "ScalarChaser", nullptr, nullptr },
+    { "ScreenFontStyle", nullptr, nullptr },
+    { "ScreenGroup", nullptr, nullptr },
+    { "SingleAxisHingeJoint", nullptr, nullptr },
+    { "SliderJoint", nullptr, nullptr },
+    { "SplinePositionInterpolator", nullptr, nullptr },
+    { "SplinePositionInterpolator2D", nullptr, nullptr },
+    { "SplineScalarInterpolator", nullptr, nullptr },
+    { "SquadOrientationInterpolator", nullptr, nullptr },
+    { "SurfaceEmitter", nullptr, nullptr },
+    { "TexCoordDamper", nullptr, nullptr },
+    { "TextureProperties", nullptr, nullptr },
+    { "TransformSensor", nullptr, nullptr },
+    { "TwoSidedMaterial", nullptr, nullptr },
+    { "UniversalJoint", nullptr, nullptr },
+    { "ViewpointGroup", nullptr, nullptr },
+    { "Viewport", nullptr, nullptr },
+    { "VolumeEmitter", nullptr, nullptr },
+    { "VolumePickSensor", nullptr, nullptr },
+    { "WindPhysicsModel", nullptr, nullptr }
+};
+
+static const FIQName attributeNameTable_3_2[] = {
+    { "DEF", nullptr, nullptr },
+    { "USE", nullptr, nullptr },
+    { "containerField", nullptr, nullptr },
+    { "fromNode", nullptr, nullptr },
+    { "fromField", nullptr, nullptr },
+    { "toNode", nullptr, nullptr },
+    { "toField", nullptr, nullptr },
+    { "name", nullptr, nullptr },
+    { "value", nullptr, nullptr },
+    { "color", nullptr, nullptr },
+    { "colorIndex", nullptr, nullptr },
+    { "coordIndex", nullptr, nullptr },
+    { "texCoordIndex", nullptr, nullptr },
+    { "normalIndex", nullptr, nullptr },
+    { "colorPerVertex", nullptr, nullptr },
+    { "normalPerVertex", nullptr, nullptr },
+    { "rotation", nullptr, nullptr },
+    { "scale", nullptr, nullptr },
+    { "center", nullptr, nullptr },
+    { "scaleOrientation", nullptr, nullptr },
+    { "translation", nullptr, nullptr },
+    { "url", nullptr, nullptr },
+    { "repeatS", nullptr, nullptr },
+    { "repeatT", nullptr, nullptr },
+    { "point", nullptr, nullptr },
+    { "vector", nullptr, nullptr },
+    { "range", nullptr, nullptr },
+    { "ambientIntensity", nullptr, nullptr },
+    { "diffuseColor", nullptr, nullptr },
+    { "emissiveColor", nullptr, nullptr },
+    { "shininess", nullptr, nullptr },
+    { "specularColor", nullptr, nullptr },
+    { "transparency", nullptr, nullptr },
+    { "whichChoice", nullptr, nullptr },
+    { "index", nullptr, nullptr },
+    { "mode", nullptr, nullptr },
+    { "source", nullptr, nullptr },
+    { "function", nullptr, nullptr },
+    { "alpha", nullptr, nullptr },
+    { "vertexCount", nullptr, nullptr },
+    { "radius", nullptr, nullptr },
+    { "size", nullptr, nullptr },
+    { "height", nullptr, nullptr },
+    { "solid", nullptr, nullptr },
+    { "ccw", nullptr, nullptr },
+    { "key", nullptr, nullptr },
+    { "keyValue", nullptr, nullptr },
+    { "enabled", nullptr, nullptr },
+    { "direction", nullptr, nullptr },
+    { "position", nullptr, nullptr },
+    { "orientation", nullptr, nullptr },
+    { "bboxCenter", nullptr, nullptr },
+    { "bboxSize", nullptr, nullptr },
+    { "AS", nullptr, nullptr },
+    { "InlineDEF", nullptr, nullptr },
+    { "accessType", nullptr, nullptr },
+    { "actionKeyPress", nullptr, nullptr },
+    { "actionKeyRelease", nullptr, nullptr },
+    { "address", nullptr, nullptr },
+    { "altKey", nullptr, nullptr },
+    { "antennaLocation", nullptr, nullptr },
+    { "antennaPatternLength", nullptr, nullptr },
+    { "antennaPatternType", nullptr, nullptr },
+    { "applicationID", nullptr, nullptr },
+    { "articulationParameterArray", nullptr, nullptr },
+    { "articulationParameterChangeIndicatorArray", nullptr, nullptr },
+    { "articulationParameterCount", nullptr, nullptr },
+    { "articulationParameterDesignatorArray", nullptr, nullptr },
+    { "articulationParameterIdPartAttachedArray", nullptr, nullptr },
+    { "articulationParameterTypeArray", nullptr, nullptr },
+    { "attenuation", nullptr, nullptr },
+    { "autoOffset", nullptr, nullptr },
+    { "avatarSize", nullptr, nullptr },
+    { "axisOfRotation", nullptr, nullptr },
+    { "backUrl", nullptr, nullptr },
+    { "beamWidth", nullptr, nullptr },
+    { "beginCap", nullptr, nullptr },
+    { "bindTime", nullptr, nullptr },
+    { "bottom", nullptr, nullptr },
+    { "bottomRadius", nullptr, nullptr },
+    { "bottomUrl", nullptr, nullptr },
+    { "centerOfMass", nullptr, nullptr },
+    { "centerOfRotation", nullptr, nullptr },
+    { "child1Url", nullptr, nullptr },
+    { "child2Url", nullptr, nullptr },
+    { "child3Url", nullptr, nullptr },
+    { "child4Url", nullptr, nullptr },
+    { "class", nullptr, nullptr },
+    { "closureType", nullptr, nullptr },
+    { "collideTime", nullptr, nullptr },
+    { "content", nullptr, nullptr },
+    { "controlKey", nullptr, nullptr },
+    { "controlPoint", nullptr, nullptr },
+    { "convex", nullptr, nullptr },
+    { "coordinateSystem", nullptr, nullptr },
+    { "copyright", nullptr, nullptr },
+    { "creaseAngle", nullptr, nullptr },
+    { "crossSection", nullptr, nullptr },
+    { "cryptoKeyID", nullptr, nullptr },
+    { "cryptoSystem", nullptr, nullptr },
+    { "cutOffAngle", nullptr, nullptr },
+    { "cycleInterval", nullptr, nullptr },
+    { "cycleTime", nullptr, nullptr },
+    { "data", nullptr, nullptr },
+    { "dataFormat", nullptr, nullptr },
+    { "dataLength", nullptr, nullptr },
+    { "dataUrl", nullptr, nullptr },
+    { "date", nullptr, nullptr },
+    { "deadReckoning", nullptr, nullptr },
+    { "deletionAllowed", nullptr, nullptr },
+    { "description", nullptr, nullptr },
+    { "detonateTime", nullptr, nullptr },
+    { "dir", nullptr, nullptr },
+    { "directOutput", nullptr, nullptr },
+    { "diskAngle", nullptr, nullptr },
+    { "displacements", nullptr, nullptr },
+    { "documentation", nullptr, nullptr },
+    { "elapsedTime", nullptr, nullptr },
+    { "ellipsoid", nullptr, nullptr },
+    { "encodingScheme", nullptr, nullptr },
+    { "endAngle", nullptr, nullptr },
+    { "endCap", nullptr, nullptr },
+    { "enterTime", nullptr, nullptr },
+    { "enteredText", nullptr, nullptr },
+    { "entityCategory", nullptr, nullptr },
+    { "entityCountry", nullptr, nullptr },
+    { "entityDomain", nullptr, nullptr },
+    { "entityExtra", nullptr, nullptr },
+    { "entityID", nullptr, nullptr },
+    { "entityKind", nullptr, nullptr },
+    { "entitySpecific", nullptr, nullptr },
+    { "entitySubCategory", nullptr, nullptr },
+    { "exitTime", nullptr, nullptr },
+    { "extent", nullptr, nullptr },
+    { "family", nullptr, nullptr },
+    { "fanCount", nullptr, nullptr },
+    { "fieldOfView", nullptr, nullptr },
+    { "filled", nullptr, nullptr },
+    { "finalText", nullptr, nullptr },
+    { "fireMissionIndex", nullptr, nullptr },
+    { "fired1", nullptr, nullptr },
+    { "fired2", nullptr, nullptr },
+    { "firedTime", nullptr, nullptr },
+    { "firingRange", nullptr, nullptr },
+    { "firingRate", nullptr, nullptr },
+    { "fogType", nullptr, nullptr },
+    { "forceID", nullptr, nullptr },
+    { "frequency", nullptr, nullptr },
+    { "frontUrl", nullptr, nullptr },
+    { "fuse", nullptr, nullptr },
+    { "geoCoords", nullptr, nullptr },
+    { "geoGridOrigin", nullptr, nullptr },
+    { "geoSystem", nullptr, nullptr },
+    { "groundAngle", nullptr, nullptr },
+    { "groundColor", nullptr, nullptr },
+    { "hatchColor", nullptr, nullptr },
+    { "hatchStyle", nullptr, nullptr },
+    { "hatched", nullptr, nullptr },
+    { "headlight", nullptr, nullptr },
+    { "horizontal", nullptr, nullptr },
+    { "horizontalDatum", nullptr, nullptr },
+    { "http-equiv", nullptr, nullptr },
+    { "image", nullptr, nullptr },
+    { "importedDEF", nullptr, nullptr },
+    { "info", nullptr, nullptr },
+    { "innerRadius", nullptr, nullptr },
+    { "inputFalse", nullptr, nullptr },
+    { "inputNegate", nullptr, nullptr },
+    { "inputSource", nullptr, nullptr },
+    { "inputTrue", nullptr, nullptr },
+    { "integerKey", nullptr, nullptr },
+    { "intensity", nullptr, nullptr },
+    { "jump", nullptr, nullptr },
+    { "justify", nullptr, nullptr },
+    { "keyPress", nullptr, nullptr },
+    { "keyRelease", nullptr, nullptr },
+    { "knot", nullptr, nullptr },
+    { "lang", nullptr, nullptr },
+    { "language", nullptr, nullptr },
+    { "leftToRight", nullptr, nullptr },
+    { "leftUrl", nullptr, nullptr },
+    { "length", nullptr, nullptr },
+    { "lengthOfModulationParameters", nullptr, nullptr },
+    { "level", nullptr, nullptr },
+    { "limitOrientation", nullptr, nullptr },
+    { "lineSegments", nullptr, nullptr },
+    { "linearAcceleration", nullptr, nullptr },
+    { "linearVelocity", nullptr, nullptr },
+    { "linetype", nullptr, nullptr },
+    { "linewidthScaleFactor", nullptr, nullptr },
+    { "llimit", nullptr, nullptr },
+    { "load", nullptr, nullptr },
+    { "loadTime", nullptr, nullptr },
+    { "localDEF", nullptr, nullptr },
+    { "location", nullptr, nullptr },
+    { "loop", nullptr, nullptr },
+    { "marking", nullptr, nullptr },
+    { "mass", nullptr, nullptr },
+    { "maxAngle", nullptr, nullptr },
+    { "maxBack", nullptr, nullptr },
+    { "maxExtent", nullptr, nullptr },
+    { "maxFront", nullptr, nullptr },
+    { "maxPosition", nullptr, nullptr },
+    { "metadataFormat", nullptr, nullptr },
+    { "minAngle", nullptr, nullptr },
+    { "minBack", nullptr, nullptr },
+    { "minFront", nullptr, nullptr },
+    { "minPosition", nullptr, nullptr },
+    { "modulationTypeDetail", nullptr, nullptr },
+    { "modulationTypeMajor", nullptr, nullptr },
+    { "modulationTypeSpreadSpectrum", nullptr, nullptr },
+    { "modulationTypeSystem", nullptr, nullptr },
+    { "momentsOfInertia", nullptr, nullptr },
+    { "multicastRelayHost", nullptr, nullptr },
+    { "multicastRelayPort", nullptr, nullptr },
+    { "munitionApplicationID", nullptr, nullptr },
+    { "munitionEndPoint", nullptr, nullptr },
+    { "munitionEntityID", nullptr, nullptr },
+    { "munitionQuantity", nullptr, nullptr },
+    { "munitionSiteID", nullptr, nullptr },
+    { "munitionStartPoint", nullptr, nullptr },
+    { "mustEvaluate", nullptr, nullptr },
+    { "navType", nullptr, nullptr },
+    { "networkMode", nullptr, nullptr },
+    { "next", nullptr, nullptr },
+    { "nodeField", nullptr, nullptr },
+    { "offset", nullptr, nullptr },
+    { "on", nullptr, nullptr },
+    { "order", nullptr, nullptr },
+    { "originator", nullptr, nullptr },
+    { "outerRadius", nullptr, nullptr },
+    { "parameter", nullptr, nullptr },
+    { "pauseTime", nullptr, nullptr },
+    { "pitch", nullptr, nullptr },
+    { "points", nullptr, nullptr },
+    { "port", nullptr, nullptr },
+    { "power", nullptr, nullptr },
+    { "previous", nullptr, nullptr },
+    { "priority", nullptr, nullptr },
+    { "profile", nullptr, nullptr },
+    { "progress", nullptr, nullptr },
+    { "protoField", nullptr, nullptr },
+    { "radioEntityTypeCategory", nullptr, nullptr },
+    { "radioEntityTypeCountry", nullptr, nullptr },
+    { "radioEntityTypeDomain", nullptr, nullptr },
+    { "radioEntityTypeKind", nullptr, nullptr },
+    { "radioEntityTypeNomenclature", nullptr, nullptr },
+    { "radioEntityTypeNomenclatureVersion", nullptr, nullptr },
+    { "radioID", nullptr, nullptr },
+    { "readInterval", nullptr, nullptr },
+    { "receivedPower", nullptr, nullptr },
+    { "receiverState", nullptr, nullptr },
+    { "reference", nullptr, nullptr },
+    { "relativeAntennaLocation", nullptr, nullptr },
+    { "resolution", nullptr, nullptr },
+    { "resumeTime", nullptr, nullptr },
+    { "rightUrl", nullptr, nullptr },
+    { "rootUrl", nullptr, nullptr },
+    { "rotateYUp", nullptr, nullptr },
+    { "rtpHeaderExpected", nullptr, nullptr },
+    { "sampleRate", nullptr, nullptr },
+    { "samples", nullptr, nullptr },
+    { "shiftKey", nullptr, nullptr },
+    { "side", nullptr, nullptr },
+    { "siteID", nullptr, nullptr },
+    { "skinCoordIndex", nullptr, nullptr },
+    { "skinCoordWeight", nullptr, nullptr },
+    { "skyAngle", nullptr, nullptr },
+    { "skyColor", nullptr, nullptr },
+    { "spacing", nullptr, nullptr },
+    { "spatialize", nullptr, nullptr },
+    { "speed", nullptr, nullptr },
+    { "speedFactor", nullptr, nullptr },
+    { "spine", nullptr, nullptr },
+    { "startAngle", nullptr, nullptr },
+    { "startTime", nullptr, nullptr },
+    { "stiffness", nullptr, nullptr },
+    { "stopTime", nullptr, nullptr },
+    { "string", nullptr, nullptr },
+    { "stripCount", nullptr, nullptr },
+    { "style", nullptr, nullptr },
+    { "summary", nullptr, nullptr },
+    { "tdlType", nullptr, nullptr },
+    { "tessellation", nullptr, nullptr },
+    { "tessellationScale", nullptr, nullptr },
+    { "time", nullptr, nullptr },
+    { "timeOut", nullptr, nullptr },
+    { "timestamp", nullptr, nullptr },
+    { "title", nullptr, nullptr },
+    { "toggle", nullptr, nullptr },
+    { "top", nullptr, nullptr },
+    { "topToBottom", nullptr, nullptr },
+    { "topUrl", nullptr, nullptr },
+    { "touchTime", nullptr, nullptr },
+    { "transmitFrequencyBandwidth", nullptr, nullptr },
+    { "transmitState", nullptr, nullptr },
+    { "transmitterApplicationID", nullptr, nullptr },
+    { "transmitterEntityID", nullptr, nullptr },
+    { "transmitterRadioID", nullptr, nullptr },
+    { "transmitterSiteID", nullptr, nullptr },
+    { "transparent", nullptr, nullptr },
+    { "triggerTime", nullptr, nullptr },
+    { "triggerTrue", nullptr, nullptr },
+    { "triggerValue", nullptr, nullptr },
+    { "type", nullptr, nullptr },
+    { "uDimension", nullptr, nullptr },
+    { "uKnot", nullptr, nullptr },
+    { "uOrder", nullptr, nullptr },
+    { "uTessellation", nullptr, nullptr },
+    { "ulimit", nullptr, nullptr },
+    { "vDimension", nullptr, nullptr },
+    { "vKnot", nullptr, nullptr },
+    { "vOrder", nullptr, nullptr },
+    { "vTessellation", nullptr, nullptr },
+    { "version", nullptr, nullptr },
+    { "verticalDatum", nullptr, nullptr },
+    { "vertices", nullptr, nullptr },
+    { "visibilityLimit", nullptr, nullptr },
+    { "visibilityRange", nullptr, nullptr },
+    { "warhead", nullptr, nullptr },
+    { "weight", nullptr, nullptr },
+    { "whichGeometry", nullptr, nullptr },
+    { "writeInterval", nullptr, nullptr },
+    { "xDimension", nullptr, nullptr },
+    { "xSpacing", nullptr, nullptr },
+    { "yScale", nullptr, nullptr },
+    { "zDimension", nullptr, nullptr },
+    { "zSpacing", nullptr, nullptr },
+    { "visible", nullptr, nullptr },
+    { "repeatR", nullptr, nullptr },
+    { "texture", nullptr, nullptr },
+    { "back", nullptr, nullptr },
+    { "front", nullptr, nullptr },
+    { "left", nullptr, nullptr },
+    { "right", nullptr, nullptr },
+    { "parts", nullptr, nullptr },
+    { "isSelected", nullptr, nullptr },
+    { "isValid", nullptr, nullptr },
+    { "numComponents", nullptr, nullptr },
+    { "depth", nullptr, nullptr },
+    { "update", nullptr, nullptr },
+    { "fogCoord", nullptr, nullptr },
+    { "texCoord", nullptr, nullptr },
+    { "activate", nullptr, nullptr },
+    { "programs", nullptr, nullptr },
+    { "matrix", nullptr, nullptr },
+    { "anchorPoint", nullptr, nullptr },
+    { "body1", nullptr, nullptr },
+    { "body2", nullptr, nullptr },
+    { "mustOutput", nullptr, nullptr },
+    { "body1AnchorPoint", nullptr, nullptr },
+    { "body2AnchorPoint", nullptr, nullptr },
+    { "plane", nullptr, nullptr },
+    { "appliedParameters", nullptr, nullptr },
+    { "bounce", nullptr, nullptr },
+    { "frictionCoefficients", nullptr, nullptr },
+    { "minBounceSpeed", nullptr, nullptr },
+    { "slipFactors", nullptr, nullptr },
+    { "softnessConstantForceMix", nullptr, nullptr },
+    { "softnessErrorCorrection", nullptr, nullptr },
+    { "surfaceSpeed", nullptr, nullptr },
+    { "isActive", nullptr, nullptr },
+    { "useGeometry", nullptr, nullptr },
+    { "set_destination", nullptr, nullptr },
+    { "set_value", nullptr, nullptr },
+    { "tau", nullptr, nullptr },
+    { "tolerance", nullptr, nullptr },
+    { "value_changed", nullptr, nullptr },
+    { "initialDestination", nullptr, nullptr },
+    { "initialValue", nullptr, nullptr },
+    { "angle", nullptr, nullptr },
+    { "variation", nullptr, nullptr },
+    { "surfaceArea", nullptr, nullptr },
+    { "frictionDirection", nullptr, nullptr },
+    { "slipCoefficients", nullptr, nullptr },
+    { "category", nullptr, nullptr },
+    { "country", nullptr, nullptr },
+    { "domain", nullptr, nullptr },
+    { "extra", nullptr, nullptr },
+    { "kind", nullptr, nullptr },
+    { "specific", nullptr, nullptr },
+    { "subcategory", nullptr, nullptr },
+    { "axis1", nullptr, nullptr },
+    { "axis2", nullptr, nullptr },
+    { "desiredAngularVelocity1", nullptr, nullptr },
+    { "desiredAngularVelocity2", nullptr, nullptr },
+    { "maxAngle1", nullptr, nullptr },
+    { "maxTorque1", nullptr, nullptr },
+    { "maxTorque2", nullptr, nullptr },
+    { "minAngle1", nullptr, nullptr },
+    { "stopBounce1", nullptr, nullptr },
+    { "stopConstantForceMix1", nullptr, nullptr },
+    { "stopErrorCorrection1", nullptr, nullptr },
+    { "suspensionErrorCorrection", nullptr, nullptr },
+    { "suspensionForce", nullptr, nullptr },
+    { "body1Axis", nullptr, nullptr },
+    { "body2Axis", nullptr, nullptr },
+    { "hinge1Angle", nullptr, nullptr },
+    { "hinge1AngleRate", nullptr, nullptr },
+    { "hinge2Angle", nullptr, nullptr },
+    { "hinge2AngleRate", nullptr, nullptr },
+    { "set_fraction", nullptr, nullptr },
+    { "easeInEaseOut", nullptr, nullptr },
+    { "modifiedFraction_changed", nullptr, nullptr },
+    { "force", nullptr, nullptr },
+    { "geoCenter", nullptr, nullptr },
+    { "centerOfRotation_changed", nullptr, nullptr },
+    { "geoCoord_changed", nullptr, nullptr },
+    { "orientation_changed", nullptr, nullptr },
+    { "position_changed", nullptr, nullptr },
+    { "isPickable", nullptr, nullptr },
+    { "viewport", nullptr, nullptr },
+    { "activeLayer", nullptr, nullptr },
+    { "align", nullptr, nullptr },
+    { "offsetUnits", nullptr, nullptr },
+    { "scaleMode", nullptr, nullptr },
+    { "sizeUnits", nullptr, nullptr },
+    { "layout", nullptr, nullptr },
+    { "objectType", nullptr, nullptr },
+    { "pickedNormal", nullptr, nullptr },
+    { "pickedPoint", nullptr, nullptr },
+    { "pickedTextureCoordinate", nullptr, nullptr },
+    { "intersectionType", nullptr, nullptr },
+    { "sortOrder", nullptr, nullptr },
+    { "axis1Angle", nullptr, nullptr },
+    { "axis1Torque", nullptr, nullptr },
+    { "axis2Angle", nullptr, nullptr },
+    { "axis2Torque", nullptr, nullptr },
+    { "axis3Angle", nullptr, nullptr },
+    { "axis3Torque", nullptr, nullptr },
+    { "enabledAxies", nullptr, nullptr },
+    { "motor1Axis", nullptr, nullptr },
+    { "motor2Axis", nullptr, nullptr },
+    { "motor3Axis", nullptr, nullptr },
+    { "stop1Bounce", nullptr, nullptr },
+    { "stop1ErrorCorrection", nullptr, nullptr },
+    { "stop2Bounce", nullptr, nullptr },
+    { "stop2ErrorCorrection", nullptr, nullptr },
+    { "stop3Bounce", nullptr, nullptr },
+    { "stop3ErrorCorrection", nullptr, nullptr },
+    { "motor1Angle", nullptr, nullptr },
+    { "motor1AngleRate", nullptr, nullptr },
+    { "motor2Angle", nullptr, nullptr },
+    { "motor2AngleRate", nullptr, nullptr },
+    { "motor3Angle", nullptr, nullptr },
+    { "motor3AngleRate", nullptr, nullptr },
+    { "autoCalc", nullptr, nullptr },
+    { "duration", nullptr, nullptr },
+    { "retainUserOffsets", nullptr, nullptr },
+    { "isBound", nullptr, nullptr },
+    { "appearance", nullptr, nullptr },
+    { "createParticles", nullptr, nullptr },
+    { "lifetimeVariation", nullptr, nullptr },
+    { "maxParticles", nullptr, nullptr },
+    { "particleLifetime", nullptr, nullptr },
+    { "particleSize", nullptr, nullptr },
+    { "colorKey", nullptr, nullptr },
+    { "geometryType", nullptr, nullptr },
+    { "texCoordKey", nullptr, nullptr },
+    { "pickable", nullptr, nullptr },
+    { "angularDampingFactor", nullptr, nullptr },
+    { "angularVelocity", nullptr, nullptr },
+    { "autoDamp", nullptr, nullptr },
+    { "autoDisable", nullptr, nullptr },
+    { "disableAngularSpeed", nullptr, nullptr },
+    { "disableLinearSpeed", nullptr, nullptr },
+    { "disableTime", nullptr, nullptr },
+    { "finiteRotationAxis", nullptr, nullptr },
+    { "fixed", nullptr, nullptr },
+    { "forces", nullptr, nullptr },
+    { "inertia", nullptr, nullptr },
+    { "linearDampingFactor", nullptr, nullptr },
+    { "torques", nullptr, nullptr },
+    { "useFiniteRotation", nullptr, nullptr },
+    { "useGlobalForce", nullptr, nullptr },
+    { "constantForceMix", nullptr, nullptr },
+    { "constantSurfaceThickness", nullptr, nullptr },
+    { "errorCorrection", nullptr, nullptr },
+    { "iterations", nullptr, nullptr },
+    { "maxCorrectionSpeed", nullptr, nullptr },
+    { "preferAccuracy", nullptr, nullptr },
+    { "pointSize", nullptr, nullptr },
+    { "stopBounce", nullptr, nullptr },
+    { "stopErrorCorrection", nullptr, nullptr },
+    { "angleRate", nullptr, nullptr },
+    { "maxSeparation", nullptr, nullptr },
+    { "minSeparation", nullptr, nullptr },
+    { "separation", nullptr, nullptr },
+    { "separationRate", nullptr, nullptr },
+    { "closed", nullptr, nullptr },
+    { "keyVelocity", nullptr, nullptr },
+    { "normalizeVelocity", nullptr, nullptr },
+    { "surface", nullptr, nullptr },
+    { "anisotropicDegree", nullptr, nullptr },
+    { "borderColor", nullptr, nullptr },
+    { "borderWidth", nullptr, nullptr },
+    { "boundaryModeS", nullptr, nullptr },
+    { "boundaryModeT", nullptr, nullptr },
+    { "boundaryModeR", nullptr, nullptr },
+    { "magnificationFilter", nullptr, nullptr },
+    { "minificationFilter", nullptr, nullptr },
+    { "textureCompression", nullptr, nullptr },
+    { "texturePriority", nullptr, nullptr },
+    { "generateMipMaps", nullptr, nullptr },
+    { "targetObject", nullptr, nullptr },
+    { "backAmbientIntensity", nullptr, nullptr },
+    { "backDiffuseColor", nullptr, nullptr },
+    { "backEmissiveColor", nullptr, nullptr },
+    { "backShininess", nullptr, nullptr },
+    { "backSpecularColor", nullptr, nullptr },
+    { "separateBackColor", nullptr, nullptr },
+    { "displayed", nullptr, nullptr },
+    { "clipBoundary", nullptr, nullptr },
+    { "internal", nullptr, nullptr },
+    { "gustiness", nullptr, nullptr },
+    { "turbulence", nullptr, nullptr }
+};
+
+FIVocabulary X3D_vocabulary_3_2 = {
+    nullptr, 0,
+    encodingAlgorithmTable_3_2, 8,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    attributeValueTable_3_2, 2,
+    nullptr, 0,
+    nullptr, 0,
+    elementNameTable_3_2, 233,
+    attributeNameTable_3_2, 516
+};
+
+static const char *encodingAlgorithmTable_3_3[] = {
+    "encoder://web3d.org/QuantizedFloatArrayEncoder",
+    "encoder://web3d.org/DeltazlibIntArrayEncoder",
+    "encoder://web3d.org/QuantizedzlibFloatArrayEncoder",
+    "encoder://web3d.org/zlibFloatArrayEncoder",
+    "encoder://web3d.org/QuantizedDoubleArrayEncoder",
+    "encoder://web3d.org/zlibDoubleArrayEncoder",
+    "encoder://web3d.org/QuantizedzlibDoubleArrayEncoder",
+    "encoder://web3d.org/RangeIntArrayEncoder"
+};
+
+static const std::shared_ptr<const FIValue> attributeValueTable_3_3[] = {
+    FIStringValue::create("false"),
+    FIStringValue::create("true")
+};
+
+static const FIQName elementNameTable_3_3[] = {
+    { "Shape", nullptr, nullptr },
+    { "Appearance", nullptr, nullptr },
+    { "Material", nullptr, nullptr },
+    { "IndexedFaceSet", nullptr, nullptr },
+    { "ProtoInstance", nullptr, nullptr },
+    { "Transform", nullptr, nullptr },
+    { "ImageTexture", nullptr, nullptr },
+    { "TextureTransform", nullptr, nullptr },
+    { "Coordinate", nullptr, nullptr },
+    { "Normal", nullptr, nullptr },
+    { "Color", nullptr, nullptr },
+    { "ColorRGBA", nullptr, nullptr },
+    { "TextureCoordinate", nullptr, nullptr },
+    { "ROUTE", nullptr, nullptr },
+    { "fieldValue", nullptr, nullptr },
+    { "Group", nullptr, nullptr },
+    { "LOD", nullptr, nullptr },
+    { "Switch", nullptr, nullptr },
+    { "Script", nullptr, nullptr },
+    { "IndexedTriangleFanSet", nullptr, nullptr },
+    { "IndexedTriangleSet", nullptr, nullptr },
+    { "IndexedTriangleStripSet", nullptr, nullptr },
+    { "MultiTexture", nullptr, nullptr },
+    { "MultiTextureCoordinate", nullptr, nullptr },
+    { "MultiTextureTransform", nullptr, nullptr },
+    { "IndexedLineSet", nullptr, nullptr },
+    { "PointSet", nullptr, nullptr },
+    { "StaticGroup", nullptr, nullptr },
+    { "Sphere", nullptr, nullptr },
+    { "Box", nullptr, nullptr },
+    { "Cone", nullptr, nullptr },
+    { "Anchor", nullptr, nullptr },
+    { "Arc2D", nullptr, nullptr },
+    { "ArcClose2D", nullptr, nullptr },
+    { "AudioClip", nullptr, nullptr },
+    { "Background", nullptr, nullptr },
+    { "Billboard", nullptr, nullptr },
+    { "BooleanFilter", nullptr, nullptr },
+    { "BooleanSequencer", nullptr, nullptr },
+    { "BooleanToggle", nullptr, nullptr },
+    { "BooleanTrigger", nullptr, nullptr },
+    { "Circle2D", nullptr, nullptr },
+    { "Collision", nullptr, nullptr },
+    { "ColorInterpolator", nullptr, nullptr },
+    { "Contour2D", nullptr, nullptr },
+    { "ContourPolyline2D", nullptr, nullptr },
+    { "CoordinateDouble", nullptr, nullptr },
+    { "CoordinateInterpolator", nullptr, nullptr },
+    { "CoordinateInterpolator2D", nullptr, nullptr },
+    { "Cylinder", nullptr, nullptr },
+    { "CylinderSensor", nullptr, nullptr },
+    { "DirectionalLight", nullptr, nullptr },
+    { "Disk2D", nullptr, nullptr },
+    { "EXPORT", nullptr, nullptr },
+    { "ElevationGrid", nullptr, nullptr },
+    { "EspduTransform", nullptr, nullptr },
+    { "ExternProtoDeclare", nullptr, nullptr },
+    { "Extrusion", nullptr, nullptr },
+    { "FillProperties", nullptr, nullptr },
+    { "Fog", nullptr, nullptr },
+    { "FontStyle", nullptr, nullptr },
+    { "GeoCoordinate", nullptr, nullptr },
+    { "GeoElevationGrid", nullptr, nullptr },
+    { "GeoLOD", nullptr, nullptr },
+    { "GeoLocation", nullptr, nullptr },
+    { "GeoMetadata", nullptr, nullptr },
+    { "GeoOrigin", nullptr, nullptr },
+    { "GeoPositionInterpolator", nullptr, nullptr },
+    { "GeoTouchSensor", nullptr, nullptr },
+    { "GeoViewpoint", nullptr, nullptr },
+    { "HAnimDisplacer", nullptr, nullptr },
+    { "HAnimHumanoid", nullptr, nullptr },
+    { "HAnimJoint", nullptr, nullptr },
+    { "HAnimSegment", nullptr, nullptr },
+    { "HAnimSite", nullptr, nullptr },
+    { "IMPORT", nullptr, nullptr },
+    { "IS", nullptr, nullptr },
+    { "Inline", nullptr, nullptr },
+    { "IntegerSequencer", nullptr, nullptr },
+    { "IntegerTrigger", nullptr, nullptr },
+    { "KeySensor", nullptr, nullptr },
+    { "LineProperties", nullptr, nullptr },
+    { "LineSet", nullptr, nullptr },
+    { "LoadSensor", nullptr, nullptr },
+    { "MetadataDouble", nullptr, nullptr },
+    { "MetadataFloat", nullptr, nullptr },
+    { "MetadataInteger", nullptr, nullptr },
+    { "MetadataSet", nullptr, nullptr },
+    { "MetadataString", nullptr, nullptr },
+    { "MovieTexture", nullptr, nullptr },
+    { "NavigationInfo", nullptr, nullptr },
+    { "NormalInterpolator", nullptr, nullptr },
+    { "NurbsCurve", nullptr, nullptr },
+    { "NurbsCurve2D", nullptr, nullptr },
+    { "NurbsOrientationInterpolator", nullptr, nullptr },
+    { "NurbsPatchSurface", nullptr, nullptr },
+    { "NurbsPositionInterpolator", nullptr, nullptr },
+    { "NurbsSet", nullptr, nullptr },
+    { "NurbsSurfaceInterpolator", nullptr, nullptr },
+    { "NurbsSweptSurface", nullptr, nullptr },
+    { "NurbsSwungSurface", nullptr, nullptr },
+    { "NurbsTextureCoordinate", nullptr, nullptr },
+    { "NurbsTrimmedSurface", nullptr, nullptr },
+    { "OrientationInterpolator", nullptr, nullptr },
+    { "PixelTexture", nullptr, nullptr },
+    { "PlaneSensor", nullptr, nullptr },
+    { "PointLight", nullptr, nullptr },
+    { "Polyline2D", nullptr, nullptr },
+    { "Polypoint2D", nullptr, nullptr },
+    { "PositionInterpolator", nullptr, nullptr },
+    { "PositionInterpolator2D", nullptr, nullptr },
+    { "ProtoBody", nullptr, nullptr },
+    { "ProtoDeclare", nullptr, nullptr },
+    { "ProtoInterface", nullptr, nullptr },
+    { "ProximitySensor", nullptr, nullptr },
+    { "ReceiverPdu", nullptr, nullptr },
+    { "Rectangle2D", nullptr, nullptr },
+    { "ScalarInterpolator", nullptr, nullptr },
+    { "Scene", nullptr, nullptr },
+    { "SignalPdu", nullptr, nullptr },
+    { "Sound", nullptr, nullptr },
+    { "SphereSensor", nullptr, nullptr },
+    { "SpotLight", nullptr, nullptr },
+    { "StringSensor", nullptr, nullptr },
+    { "Text", nullptr, nullptr },
+    { "TextureBackground", nullptr, nullptr },
+    { "TextureCoordinateGenerator", nullptr, nullptr },
+    { "TimeSensor", nullptr, nullptr },
+    { "TimeTrigger", nullptr, nullptr },
+    { "TouchSensor", nullptr, nullptr },
+    { "TransmitterPdu", nullptr, nullptr },
+    { "TriangleFanSet", nullptr, nullptr },
+    { "TriangleSet", nullptr, nullptr },
+    { "TriangleSet2D", nullptr, nullptr },
+    { "TriangleStripSet", nullptr, nullptr },
+    { "Viewpoint", nullptr, nullptr },
+    { "VisibilitySensor", nullptr, nullptr },
+    { "WorldInfo", nullptr, nullptr },
+    { "X3D", nullptr, nullptr },
+    { "component", nullptr, nullptr },
+    { "connect", nullptr, nullptr },
+    { "field", nullptr, nullptr },
+    { "head", nullptr, nullptr },
+    { "humanoidBodyType", nullptr, nullptr },
+    { "meta", nullptr, nullptr },
+    { "CADAssembly", nullptr, nullptr },
+    { "CADFace", nullptr, nullptr },
+    { "CADLayer", nullptr, nullptr },
+    { "CADPart", nullptr, nullptr },
+    { "ComposedCubeMapTexture", nullptr, nullptr },
+    { "ComposedShader", nullptr, nullptr },
+    { "ComposedTexture3D", nullptr, nullptr },
+    { "FloatVertexAttribute", nullptr, nullptr },
+    { "FogCoordinate", nullptr, nullptr },
+    { "GeneratedCubeMapTexture", nullptr, nullptr },
+    { "ImageCubeMapTexture", nullptr, nullptr },
+    { "ImageTexture3D", nullptr, nullptr },
+    { "IndexedQuadSet", nullptr, nullptr },
+    { "LocalFog", nullptr, nullptr },
+    { "Matrix3VertexAttribute", nullptr, nullptr },
+    { "Matrix4VertexAttribute", nullptr, nullptr },
+    { "PackagedShader", nullptr, nullptr },
+    { "PixelTexture3D", nullptr, nullptr },
+    { "ProgramShader", nullptr, nullptr },
+    { "QuadSet", nullptr, nullptr },
+    { "ShaderPart", nullptr, nullptr },
+    { "ShaderProgram", nullptr, nullptr },
+    { "TextureCoordinate3D", nullptr, nullptr },
+    { "TextureCoordinate4D", nullptr, nullptr },
+    { "TextureTransform3D", nullptr, nullptr },
+    { "TextureTransformMatrix3D", nullptr, nullptr },
+    { "BallJoint", nullptr, nullptr },
+    { "BoundedPhysicsModel", nullptr, nullptr },
+    { "ClipPlane", nullptr, nullptr },
+    { "CollidableOffset", nullptr, nullptr },
+    { "CollidableShape", nullptr, nullptr },
+    { "CollisionCollection", nullptr, nullptr },
+    { "CollisionSensor", nullptr, nullptr },
+    { "CollisionSpace", nullptr, nullptr },
+    { "ColorDamper", nullptr, nullptr },
+    { "ConeEmitter", nullptr, nullptr },
+    { "Contact", nullptr, nullptr },
+    { "CoordinateDamper", nullptr, nullptr },
+    { "DISEntityManager", nullptr, nullptr },
+    { "DISEntityTypeMapping", nullptr, nullptr },
+    { "DoubleAxisHingeJoint", nullptr, nullptr },
+    { "EaseInEaseOut", nullptr, nullptr },
+    { "ExplosionEmitter", nullptr, nullptr },
+    { "ForcePhysicsModel", nullptr, nullptr },
+    { "GeoProximitySensor", nullptr, nullptr },
+    { "GeoTransform", nullptr, nullptr },
+    { "Layer", nullptr, nullptr },
+    { "LayerSet", nullptr, nullptr },
+    { "Layout", nullptr, nullptr },
+    { "LayoutGroup", nullptr, nullptr },
+    { "LayoutLayer", nullptr, nullptr },
+    { "LinePickSensor", nullptr, nullptr },
+    { "MotorJoint", nullptr, nullptr },
+    { "OrientationChaser", nullptr, nullptr },
+    { "OrientationDamper", nullptr, nullptr },
+    { "OrthoViewpoint", nullptr, nullptr },
+    { "ParticleSystem", nullptr, nullptr },
+    { "PickableGroup", nullptr, nullptr },
+    { "PointEmitter", nullptr, nullptr },
+    { "PointPickSensor", nullptr, nullptr },
+    { "PolylineEmitter", nullptr, nullptr },
+    { "PositionChaser", nullptr, nullptr },
+    { "PositionChaser2D", nullptr, nullptr },
+    { "PositionDamper", nullptr, nullptr },
+    { "PositionDamper2D", nullptr, nullptr },
+    { "PrimitivePickSensor", nullptr, nullptr },
+    { "RigidBody", nullptr, nullptr },
+    { "RigidBodyCollection", nullptr, nullptr },
+    { "ScalarChaser", nullptr, nullptr },
+    { "ScreenFontStyle", nullptr, nullptr },
+    { "ScreenGroup", nullptr, nullptr },
+    { "SingleAxisHingeJoint", nullptr, nullptr },
+    { "SliderJoint", nullptr, nullptr },
+    { "SplinePositionInterpolator", nullptr, nullptr },
+    { "SplinePositionInterpolator2D", nullptr, nullptr },
+    { "SplineScalarInterpolator", nullptr, nullptr },
+    { "SquadOrientationInterpolator", nullptr, nullptr },
+    { "SurfaceEmitter", nullptr, nullptr },
+    { "TexCoordDamper2D", nullptr, nullptr },
+    { "TextureProperties", nullptr, nullptr },
+    { "TransformSensor", nullptr, nullptr },
+    { "TwoSidedMaterial", nullptr, nullptr },
+    { "UniversalJoint", nullptr, nullptr },
+    { "ViewpointGroup", nullptr, nullptr },
+    { "Viewport", nullptr, nullptr },
+    { "VolumeEmitter", nullptr, nullptr },
+    { "VolumePickSensor", nullptr, nullptr },
+    { "WindPhysicsModel", nullptr, nullptr },
+    { "BlendedVolumeStyle", nullptr, nullptr },
+    { "BoundaryEnhancementVolumeStyle", nullptr, nullptr },
+    { "CartoonVolumeStyle", nullptr, nullptr },
+    { "ComposedVolumeStyle", nullptr, nullptr },
+    { "EdgeEnhancementVolumeStyle", nullptr, nullptr },
+    { "IsoSurfaceVolumeData", nullptr, nullptr },
+    { "MetadataBoolean", nullptr, nullptr },
+    { "OpacityMapVolumeStyle", nullptr, nullptr },
+    { "ProjectionVolumeStyle", nullptr, nullptr },
+    { "SegmentedVolumeData", nullptr, nullptr },
+    { "ShadedVolumeStyle", nullptr, nullptr },
+    { "SilhouetteEnhancementVolumeStyle", nullptr, nullptr },
+    { "ToneMappedVolumeStyle", nullptr, nullptr },
+    { "VolumeData", nullptr, nullptr },
+    { "ColorChaser", nullptr, nullptr },
+    { "CoordinateChaser", nullptr, nullptr },
+    { "ScalarDamper", nullptr, nullptr },
+    { "TexCoordChaser2D", nullptr, nullptr },
+    { "unit", nullptr, nullptr }
+};
+
+static const FIQName attributeNameTable_3_3[] = {
+    { "DEF", nullptr, nullptr },
+    { "USE", nullptr, nullptr },
+    { "containerField", nullptr, nullptr },
+    { "fromNode", nullptr, nullptr },
+    { "fromField", nullptr, nullptr },
+    { "toNode", nullptr, nullptr },
+    { "toField", nullptr, nullptr },
+    { "name", nullptr, nullptr },
+    { "value", nullptr, nullptr },
+    { "color", nullptr, nullptr },
+    { "colorIndex", nullptr, nullptr },
+    { "coordIndex", nullptr, nullptr },
+    { "texCoordIndex", nullptr, nullptr },
+    { "normalIndex", nullptr, nullptr },
+    { "colorPerVertex", nullptr, nullptr },
+    { "normalPerVertex", nullptr, nullptr },
+    { "rotation", nullptr, nullptr },
+    { "scale", nullptr, nullptr },
+    { "center", nullptr, nullptr },
+    { "scaleOrientation", nullptr, nullptr },
+    { "translation", nullptr, nullptr },
+    { "url", nullptr, nullptr },
+    { "repeatS", nullptr, nullptr },
+    { "repeatT", nullptr, nullptr },
+    { "point", nullptr, nullptr },
+    { "vector", nullptr, nullptr },
+    { "range", nullptr, nullptr },
+    { "ambientIntensity", nullptr, nullptr },
+    { "diffuseColor", nullptr, nullptr },
+    { "emissiveColor", nullptr, nullptr },
+    { "shininess", nullptr, nullptr },
+    { "specularColor", nullptr, nullptr },
+    { "transparency", nullptr, nullptr },
+    { "whichChoice", nullptr, nullptr },
+    { "index", nullptr, nullptr },
+    { "mode", nullptr, nullptr },
+    { "source", nullptr, nullptr },
+    { "function", nullptr, nullptr },
+    { "alpha", nullptr, nullptr },
+    { "vertexCount", nullptr, nullptr },
+    { "radius", nullptr, nullptr },
+    { "size", nullptr, nullptr },
+    { "height", nullptr, nullptr },
+    { "solid", nullptr, nullptr },
+    { "ccw", nullptr, nullptr },
+    { "key", nullptr, nullptr },
+    { "keyValue", nullptr, nullptr },
+    { "enabled", nullptr, nullptr },
+    { "direction", nullptr, nullptr },
+    { "position", nullptr, nullptr },
+    { "orientation", nullptr, nullptr },
+    { "bboxCenter", nullptr, nullptr },
+    { "bboxSize", nullptr, nullptr },
+    { "AS", nullptr, nullptr },
+    { "InlineDEF", nullptr, nullptr },
+    { "accessType", nullptr, nullptr },
+    { "actionKeyPress", nullptr, nullptr },
+    { "actionKeyRelease", nullptr, nullptr },
+    { "address", nullptr, nullptr },
+    { "altKey", nullptr, nullptr },
+    { "antennaLocation", nullptr, nullptr },
+    { "antennaPatternLength", nullptr, nullptr },
+    { "antennaPatternType", nullptr, nullptr },
+    { "applicationID", nullptr, nullptr },
+    { "articulationParameterArray", nullptr, nullptr },
+    { "articulationParameterChangeIndicatorArray", nullptr, nullptr },
+    { "articulationParameterCount", nullptr, nullptr },
+    { "articulationParameterDesignatorArray", nullptr, nullptr },
+    { "articulationParameterIdPartAttachedArray", nullptr, nullptr },
+    { "articulationParameterTypeArray", nullptr, nullptr },
+    { "attenuation", nullptr, nullptr },
+    { "autoOffset", nullptr, nullptr },
+    { "avatarSize", nullptr, nullptr },
+    { "axisOfRotation", nullptr, nullptr },
+    { "backUrl", nullptr, nullptr },
+    { "beamWidth", nullptr, nullptr },
+    { "beginCap", nullptr, nullptr },
+    { "bindTime", nullptr, nullptr },
+    { "bottom", nullptr, nullptr },
+    { "bottomRadius", nullptr, nullptr },
+    { "bottomUrl", nullptr, nullptr },
+    { "centerOfMass", nullptr, nullptr },
+    { "centerOfRotation", nullptr, nullptr },
+    { "child1Url", nullptr, nullptr },
+    { "child2Url", nullptr, nullptr },
+    { "child3Url", nullptr, nullptr },
+    { "child4Url", nullptr, nullptr },
+    { "class", nullptr, nullptr },
+    { "closureType", nullptr, nullptr },
+    { "collideTime", nullptr, nullptr },
+    { "content", nullptr, nullptr },
+    { "controlKey", nullptr, nullptr },
+    { "controlPoint", nullptr, nullptr },
+    { "convex", nullptr, nullptr },
+    { "coordinateSystem", nullptr, nullptr },
+    { "copyright", nullptr, nullptr },
+    { "creaseAngle", nullptr, nullptr },
+    { "crossSection", nullptr, nullptr },
+    { "cryptoKeyID", nullptr, nullptr },
+    { "cryptoSystem", nullptr, nullptr },
+    { "cutOffAngle", nullptr, nullptr },
+    { "cycleInterval", nullptr, nullptr },
+    { "cycleTime", nullptr, nullptr },
+    { "data", nullptr, nullptr },
+    { "dataFormat", nullptr, nullptr },
+    { "dataLength", nullptr, nullptr },
+    { "dataUrl", nullptr, nullptr },
+    { "date", nullptr, nullptr },
+    { "deadReckoning", nullptr, nullptr },
+    { "deletionAllowed", nullptr, nullptr },
+    { "description", nullptr, nullptr },
+    { "detonateTime", nullptr, nullptr },
+    { "dir", nullptr, nullptr },
+    { "directOutput", nullptr, nullptr },
+    { "diskAngle", nullptr, nullptr },
+    { "displacements", nullptr, nullptr },
+    { "documentation", nullptr, nullptr },
+    { "elapsedTime", nullptr, nullptr },
+    { "ellipsoid", nullptr, nullptr },
+    { "encodingScheme", nullptr, nullptr },
+    { "endAngle", nullptr, nullptr },
+    { "endCap", nullptr, nullptr },
+    { "enterTime", nullptr, nullptr },
+    { "enteredText", nullptr, nullptr },
+    { "entityCategory", nullptr, nullptr },
+    { "entityCountry", nullptr, nullptr },
+    { "entityDomain", nullptr, nullptr },
+    { "entityExtra", nullptr, nullptr },
+    { "entityID", nullptr, nullptr },
+    { "entityKind", nullptr, nullptr },
+    { "entitySpecific", nullptr, nullptr },
+    { "entitySubCategory", nullptr, nullptr },
+    { "exitTime", nullptr, nullptr },
+    { "extent", nullptr, nullptr },
+    { "family", nullptr, nullptr },
+    { "fanCount", nullptr, nullptr },
+    { "fieldOfView", nullptr, nullptr },
+    { "filled", nullptr, nullptr },
+    { "finalText", nullptr, nullptr },
+    { "fireMissionIndex", nullptr, nullptr },
+    { "fired1", nullptr, nullptr },
+    { "fired2", nullptr, nullptr },
+    { "firedTime", nullptr, nullptr },
+    { "firingRange", nullptr, nullptr },
+    { "firingRate", nullptr, nullptr },
+    { "fogType", nullptr, nullptr },
+    { "forceID", nullptr, nullptr },
+    { "frequency", nullptr, nullptr },
+    { "frontUrl", nullptr, nullptr },
+    { "fuse", nullptr, nullptr },
+    { "geoCoords", nullptr, nullptr },
+    { "geoGridOrigin", nullptr, nullptr },
+    { "geoSystem", nullptr, nullptr },
+    { "groundAngle", nullptr, nullptr },
+    { "groundColor", nullptr, nullptr },
+    { "hatchColor", nullptr, nullptr },
+    { "hatchStyle", nullptr, nullptr },
+    { "hatched", nullptr, nullptr },
+    { "headlight", nullptr, nullptr },
+    { "horizontal", nullptr, nullptr },
+    { "horizontalDatum", nullptr, nullptr },
+    { "http-equiv", nullptr, nullptr },
+    { "image", nullptr, nullptr },
+    { "importedDEF", nullptr, nullptr },
+    { "info", nullptr, nullptr },
+    { "innerRadius", nullptr, nullptr },
+    { "inputFalse", nullptr, nullptr },
+    { "inputNegate", nullptr, nullptr },
+    { "inputSource", nullptr, nullptr },
+    { "inputTrue", nullptr, nullptr },
+    { "integerKey", nullptr, nullptr },
+    { "intensity", nullptr, nullptr },
+    { "jump", nullptr, nullptr },
+    { "justify", nullptr, nullptr },
+    { "keyPress", nullptr, nullptr },
+    { "keyRelease", nullptr, nullptr },
+    { "knot", nullptr, nullptr },
+    { "lang", nullptr, nullptr },
+    { "language", nullptr, nullptr },
+    { "leftToRight", nullptr, nullptr },
+    { "leftUrl", nullptr, nullptr },
+    { "length", nullptr, nullptr },
+    { "lengthOfModulationParameters", nullptr, nullptr },
+    { "level", nullptr, nullptr },
+    { "limitOrientation", nullptr, nullptr },
+    { "lineSegments", nullptr, nullptr },
+    { "linearAcceleration", nullptr, nullptr },
+    { "linearVelocity", nullptr, nullptr },
+    { "linetype", nullptr, nullptr },
+    { "linewidthScaleFactor", nullptr, nullptr },
+    { "llimit", nullptr, nullptr },
+    { "load", nullptr, nullptr },
+    { "loadTime", nullptr, nullptr },
+    { "localDEF", nullptr, nullptr },
+    { "location", nullptr, nullptr },
+    { "loop", nullptr, nullptr },
+    { "marking", nullptr, nullptr },
+    { "mass", nullptr, nullptr },
+    { "maxAngle", nullptr, nullptr },
+    { "maxBack", nullptr, nullptr },
+    { "maxExtent", nullptr, nullptr },
+    { "maxFront", nullptr, nullptr },
+    { "maxPosition", nullptr, nullptr },
+    { "metadataFormat", nullptr, nullptr },
+    { "minAngle", nullptr, nullptr },
+    { "minBack", nullptr, nullptr },
+    { "minFront", nullptr, nullptr },
+    { "minPosition", nullptr, nullptr },
+    { "modulationTypeDetail", nullptr, nullptr },
+    { "modulationTypeMajor", nullptr, nullptr },
+    { "modulationTypeSpreadSpectrum", nullptr, nullptr },
+    { "modulationTypeSystem", nullptr, nullptr },
+    { "momentsOfInertia", nullptr, nullptr },
+    { "multicastRelayHost", nullptr, nullptr },
+    { "multicastRelayPort", nullptr, nullptr },
+    { "munitionApplicationID", nullptr, nullptr },
+    { "munitionEndPoint", nullptr, nullptr },
+    { "munitionEntityID", nullptr, nullptr },
+    { "munitionQuantity", nullptr, nullptr },
+    { "munitionSiteID", nullptr, nullptr },
+    { "munitionStartPoint", nullptr, nullptr },
+    { "mustEvaluate", nullptr, nullptr },
+    { "navType", nullptr, nullptr },
+    { "networkMode", nullptr, nullptr },
+    { "next", nullptr, nullptr },
+    { "nodeField", nullptr, nullptr },
+    { "offset", nullptr, nullptr },
+    { "on", nullptr, nullptr },
+    { "order", nullptr, nullptr },
+    { "originator", nullptr, nullptr },
+    { "outerRadius", nullptr, nullptr },
+    { "parameter", nullptr, nullptr },
+    { "pauseTime", nullptr, nullptr },
+    { "pitch", nullptr, nullptr },
+    { "points", nullptr, nullptr },
+    { "port", nullptr, nullptr },
+    { "power", nullptr, nullptr },
+    { "previous", nullptr, nullptr },
+    { "priority", nullptr, nullptr },
+    { "profile", nullptr, nullptr },
+    { "progress", nullptr, nullptr },
+    { "protoField", nullptr, nullptr },
+    { "radioEntityTypeCategory", nullptr, nullptr },
+    { "radioEntityTypeCountry", nullptr, nullptr },
+    { "radioEntityTypeDomain", nullptr, nullptr },
+    { "radioEntityTypeKind", nullptr, nullptr },
+    { "radioEntityTypeNomenclature", nullptr, nullptr },
+    { "radioEntityTypeNomenclatureVersion", nullptr, nullptr },
+    { "radioID", nullptr, nullptr },
+    { "readInterval", nullptr, nullptr },
+    { "receivedPower", nullptr, nullptr },
+    { "receiverState", nullptr, nullptr },
+    { "reference", nullptr, nullptr },
+    { "relativeAntennaLocation", nullptr, nullptr },
+    { "resolution", nullptr, nullptr },
+    { "resumeTime", nullptr, nullptr },
+    { "rightUrl", nullptr, nullptr },
+    { "rootUrl", nullptr, nullptr },
+    { "rotateYUp", nullptr, nullptr },
+    { "rtpHeaderExpected", nullptr, nullptr },
+    { "sampleRate", nullptr, nullptr },
+    { "samples", nullptr, nullptr },
+    { "shiftKey", nullptr, nullptr },
+    { "side", nullptr, nullptr },
+    { "siteID", nullptr, nullptr },
+    { "skinCoordIndex", nullptr, nullptr },
+    { "skinCoordWeight", nullptr, nullptr },
+    { "skyAngle", nullptr, nullptr },
+    { "skyColor", nullptr, nullptr },
+    { "spacing", nullptr, nullptr },
+    { "spatialize", nullptr, nullptr },
+    { "speed", nullptr, nullptr },
+    { "speedFactor", nullptr, nullptr },
+    { "spine", nullptr, nullptr },
+    { "startAngle", nullptr, nullptr },
+    { "startTime", nullptr, nullptr },
+    { "stiffness", nullptr, nullptr },
+    { "stopTime", nullptr, nullptr },
+    { "string", nullptr, nullptr },
+    { "stripCount", nullptr, nullptr },
+    { "style", nullptr, nullptr },
+    { "summary", nullptr, nullptr },
+    { "tdlType", nullptr, nullptr },
+    { "tessellation", nullptr, nullptr },
+    { "tessellationScale", nullptr, nullptr },
+    { "time", nullptr, nullptr },
+    { "timeOut", nullptr, nullptr },
+    { "timestamp", nullptr, nullptr },
+    { "title", nullptr, nullptr },
+    { "toggle", nullptr, nullptr },
+    { "top", nullptr, nullptr },
+    { "topToBottom", nullptr, nullptr },
+    { "topUrl", nullptr, nullptr },
+    { "touchTime", nullptr, nullptr },
+    { "transmitFrequencyBandwidth", nullptr, nullptr },
+    { "transmitState", nullptr, nullptr },
+    { "transmitterApplicationID", nullptr, nullptr },
+    { "transmitterEntityID", nullptr, nullptr },
+    { "transmitterRadioID", nullptr, nullptr },
+    { "transmitterSiteID", nullptr, nullptr },
+    { "transparent", nullptr, nullptr },
+    { "triggerTime", nullptr, nullptr },
+    { "triggerTrue", nullptr, nullptr },
+    { "triggerValue", nullptr, nullptr },
+    { "type", nullptr, nullptr },
+    { "uDimension", nullptr, nullptr },
+    { "uKnot", nullptr, nullptr },
+    { "uOrder", nullptr, nullptr },
+    { "uTessellation", nullptr, nullptr },
+    { "ulimit", nullptr, nullptr },
+    { "vDimension", nullptr, nullptr },
+    { "vKnot", nullptr, nullptr },
+    { "vOrder", nullptr, nullptr },
+    { "vTessellation", nullptr, nullptr },
+    { "version", nullptr, nullptr },
+    { "verticalDatum", nullptr, nullptr },
+    { "vertices", nullptr, nullptr },
+    { "visibilityLimit", nullptr, nullptr },
+    { "visibilityRange", nullptr, nullptr },
+    { "warhead", nullptr, nullptr },
+    { "weight", nullptr, nullptr },
+    { "whichGeometry", nullptr, nullptr },
+    { "writeInterval", nullptr, nullptr },
+    { "xDimension", nullptr, nullptr },
+    { "xSpacing", nullptr, nullptr },
+    { "yScale", nullptr, nullptr },
+    { "zDimension", nullptr, nullptr },
+    { "zSpacing", nullptr, nullptr },
+    { "visible", nullptr, nullptr },
+    { "repeatR", nullptr, nullptr },
+    { "texture", nullptr, nullptr },
+    { "back", nullptr, nullptr },
+    { "front", nullptr, nullptr },
+    { "left", nullptr, nullptr },
+    { "right", nullptr, nullptr },
+    { "parts", nullptr, nullptr },
+    { "isSelected", nullptr, nullptr },
+    { "isValid", nullptr, nullptr },
+    { "numComponents", nullptr, nullptr },
+    { "depth", nullptr, nullptr },
+    { "update", nullptr, nullptr },
+    { "fogCoord", nullptr, nullptr },
+    { "texCoord", nullptr, nullptr },
+    { "activate", nullptr, nullptr },
+    { "programs", nullptr, nullptr },
+    { "matrix", nullptr, nullptr },
+    { "anchorPoint", nullptr, nullptr },
+    { "body1", nullptr, nullptr },
+    { "body2", nullptr, nullptr },
+    { "forceOutput", nullptr, nullptr },
+    { "body1AnchorPoint", nullptr, nullptr },
+    { "body2AnchorPoint", nullptr, nullptr },
+    { "plane", nullptr, nullptr },
+    { "appliedParameters", nullptr, nullptr },
+    { "bounce", nullptr, nullptr },
+    { "frictionCoefficients", nullptr, nullptr },
+    { "minBounceSpeed", nullptr, nullptr },
+    { "slipFactors", nullptr, nullptr },
+    { "softnessConstantForceMix", nullptr, nullptr },
+    { "softnessErrorCorrection", nullptr, nullptr },
+    { "surfaceSpeed", nullptr, nullptr },
+    { "isActive", nullptr, nullptr },
+    { "useGeometry", nullptr, nullptr },
+    { "set_destination", nullptr, nullptr },
+    { "set_value", nullptr, nullptr },
+    { "tau", nullptr, nullptr },
+    { "tolerance", nullptr, nullptr },
+    { "value_changed", nullptr, nullptr },
+    { "initialDestination", nullptr, nullptr },
+    { "initialValue", nullptr, nullptr },
+    { "angle", nullptr, nullptr },
+    { "variation", nullptr, nullptr },
+    { "surfaceArea", nullptr, nullptr },
+    { "frictionDirection", nullptr, nullptr },
+    { "slipCoefficients", nullptr, nullptr },
+    { "category", nullptr, nullptr },
+    { "country", nullptr, nullptr },
+    { "domain", nullptr, nullptr },
+    { "extra", nullptr, nullptr },
+    { "kind", nullptr, nullptr },
+    { "specific", nullptr, nullptr },
+    { "subcategory", nullptr, nullptr },
+    { "axis1", nullptr, nullptr },
+    { "axis2", nullptr, nullptr },
+    { "desiredAngularVelocity1", nullptr, nullptr },
+    { "desiredAngularVelocity2", nullptr, nullptr },
+    { "maxAngle1", nullptr, nullptr },
+    { "maxTorque1", nullptr, nullptr },
+    { "maxTorque2", nullptr, nullptr },
+    { "minAngle1", nullptr, nullptr },
+    { "stopBounce1", nullptr, nullptr },
+    { "stopConstantForceMix1", nullptr, nullptr },
+    { "stopErrorCorrection1", nullptr, nullptr },
+    { "suspensionErrorCorrection", nullptr, nullptr },
+    { "suspensionForce", nullptr, nullptr },
+    { "body1Axis", nullptr, nullptr },
+    { "body2Axis", nullptr, nullptr },
+    { "hinge1Angle", nullptr, nullptr },
+    { "hinge1AngleRate", nullptr, nullptr },
+    { "hinge2Angle", nullptr, nullptr },
+    { "hinge2AngleRate", nullptr, nullptr },
+    { "set_fraction", nullptr, nullptr },
+    { "easeInEaseOut", nullptr, nullptr },
+    { "modifiedFraction_changed", nullptr, nullptr },
+    { "force", nullptr, nullptr },
+    { "geoCenter", nullptr, nullptr },
+    { "centerOfRotation_changed", nullptr, nullptr },
+    { "geoCoord_changed", nullptr, nullptr },
+    { "orientation_changed", nullptr, nullptr },
+    { "position_changed", nullptr, nullptr },
+    { "isPickable", nullptr, nullptr },
+    { "viewport", nullptr, nullptr },
+    { "activeLayer", nullptr, nullptr },
+    { "align", nullptr, nullptr },
+    { "offsetUnits", nullptr, nullptr },
+    { "scaleMode", nullptr, nullptr },
+    { "sizeUnits", nullptr, nullptr },
+    { "layout", nullptr, nullptr },
+    { "objectType", nullptr, nullptr },
+    { "pickedNormal", nullptr, nullptr },
+    { "pickedPoint", nullptr, nullptr },
+    { "pickedTextureCoordinate", nullptr, nullptr },
+    { "intersectionType", nullptr, nullptr },
+    { "sortOrder", nullptr, nullptr },
+    { "axis1Angle", nullptr, nullptr },
+    { "axis1Torque", nullptr, nullptr },
+    { "axis2Angle", nullptr, nullptr },
+    { "axis2Torque", nullptr, nullptr },
+    { "axis3Angle", nullptr, nullptr },
+    { "axis3Torque", nullptr, nullptr },
+    { "enabledAxies", nullptr, nullptr },
+    { "motor1Axis", nullptr, nullptr },
+    { "motor2Axis", nullptr, nullptr },
+    { "motor3Axis", nullptr, nullptr },
+    { "stop1Bounce", nullptr, nullptr },
+    { "stop1ErrorCorrection", nullptr, nullptr },
+    { "stop2Bounce", nullptr, nullptr },
+    { "stop2ErrorCorrection", nullptr, nullptr },
+    { "stop3Bounce", nullptr, nullptr },
+    { "stop3ErrorCorrection", nullptr, nullptr },
+    { "motor1Angle", nullptr, nullptr },
+    { "motor1AngleRate", nullptr, nullptr },
+    { "motor2Angle", nullptr, nullptr },
+    { "motor2AngleRate", nullptr, nullptr },
+    { "motor3Angle", nullptr, nullptr },
+    { "motor3AngleRate", nullptr, nullptr },
+    { "autoCalc", nullptr, nullptr },
+    { "duration", nullptr, nullptr },
+    { "retainUserOffsets", nullptr, nullptr },
+    { "isBound", nullptr, nullptr },
+    { "appearance", nullptr, nullptr },
+    { "createParticles", nullptr, nullptr },
+    { "lifetimeVariation", nullptr, nullptr },
+    { "maxParticles", nullptr, nullptr },
+    { "particleLifetime", nullptr, nullptr },
+    { "particleSize", nullptr, nullptr },
+    { "colorKey", nullptr, nullptr },
+    { "geometryType", nullptr, nullptr },
+    { "texCoordKey", nullptr, nullptr },
+    { "pickable", nullptr, nullptr },
+    { "angularDampingFactor", nullptr, nullptr },
+    { "angularVelocity", nullptr, nullptr },
+    { "autoDamp", nullptr, nullptr },
+    { "autoDisable", nullptr, nullptr },
+    { "disableAngularSpeed", nullptr, nullptr },
+    { "disableLinearSpeed", nullptr, nullptr },
+    { "disableTime", nullptr, nullptr },
+    { "finiteRotationAxis", nullptr, nullptr },
+    { "fixed", nullptr, nullptr },
+    { "forces", nullptr, nullptr },
+    { "inertia", nullptr, nullptr },
+    { "linearDampingFactor", nullptr, nullptr },
+    { "torques", nullptr, nullptr },
+    { "useFiniteRotation", nullptr, nullptr },
+    { "useGlobalForce", nullptr, nullptr },
+    { "constantForceMix", nullptr, nullptr },
+    { "constantSurfaceThickness", nullptr, nullptr },
+    { "errorCorrection", nullptr, nullptr },
+    { "iterations", nullptr, nullptr },
+    { "maxCorrectionSpeed", nullptr, nullptr },
+    { "preferAccuracy", nullptr, nullptr },
+    { "pointSize", nullptr, nullptr },
+    { "stopBounce", nullptr, nullptr },
+    { "stopErrorCorrection", nullptr, nullptr },
+    { "angleRate", nullptr, nullptr },
+    { "maxSeparation", nullptr, nullptr },
+    { "minSeparation", nullptr, nullptr },
+    { "separation", nullptr, nullptr },
+    { "separationRate", nullptr, nullptr },
+    { "closed", nullptr, nullptr },
+    { "keyVelocity", nullptr, nullptr },
+    { "normalizeVelocity", nullptr, nullptr },
+    { "surface", nullptr, nullptr },
+    { "anisotropicDegree", nullptr, nullptr },
+    { "borderColor", nullptr, nullptr },
+    { "borderWidth", nullptr, nullptr },
+    { "boundaryModeS", nullptr, nullptr },
+    { "boundaryModeT", nullptr, nullptr },
+    { "boundaryModeR", nullptr, nullptr },
+    { "magnificationFilter", nullptr, nullptr },
+    { "minificationFilter", nullptr, nullptr },
+    { "textureCompression", nullptr, nullptr },
+    { "texturePriority", nullptr, nullptr },
+    { "generateMipMaps", nullptr, nullptr },
+    { "targetObject", nullptr, nullptr },
+    { "backAmbientIntensity", nullptr, nullptr },
+    { "backDiffuseColor", nullptr, nullptr },
+    { "backEmissiveColor", nullptr, nullptr },
+    { "backShininess", nullptr, nullptr },
+    { "backSpecularColor", nullptr, nullptr },
+    { "separateBackColor", nullptr, nullptr },
+    { "displayed", nullptr, nullptr },
+    { "clipBoundary", nullptr, nullptr },
+    { "internal", nullptr, nullptr },
+    { "gustiness", nullptr, nullptr },
+    { "turbulence", nullptr, nullptr },
+    { "unitCategory", nullptr, nullptr },
+    { "unitName", nullptr, nullptr },
+    { "unitConversionFactor", nullptr, nullptr },
+    { "weightConstant1", nullptr, nullptr },
+    { "weightConstant2", nullptr, nullptr },
+    { "weightFunction1", nullptr, nullptr },
+    { "weightFunction2", nullptr, nullptr },
+    { "boundaryOpacity", nullptr, nullptr },
+    { "opacityFactor", nullptr, nullptr },
+    { "retainedOpacity", nullptr, nullptr },
+    { "colorSteps", nullptr, nullptr },
+    { "orthogonalColor", nullptr, nullptr },
+    { "parallelColor", nullptr, nullptr },
+    { "ordered", nullptr, nullptr },
+    { "edgeColor", nullptr, nullptr },
+    { "gradientThreshold", nullptr, nullptr },
+    { "contourStepSize", nullptr, nullptr },
+    { "dimensions", nullptr, nullptr },
+    { "surfaceTolerance", nullptr, nullptr },
+    { "surfaceValues", nullptr, nullptr },
+    { "intensityThreshold", nullptr, nullptr },
+    { "segmentEnabled", nullptr, nullptr },
+    { "lighting", nullptr, nullptr },
+    { "shadows", nullptr, nullptr },
+    { "phaseFunction", nullptr, nullptr },
+    { "silhouetteBoundaryOpacity", nullptr, nullptr },
+    { "silhouetteRetainedOpacity", nullptr, nullptr },
+    { "silhouetteSharpness", nullptr, nullptr },
+    { "coolColor", nullptr, nullptr },
+    { "warmColor", nullptr, nullptr }
+};
+
+FIVocabulary X3D_vocabulary_3_3 = {
+    nullptr, 0,
+    encodingAlgorithmTable_3_3, 8,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    nullptr, 0,
+    attributeValueTable_3_3, 2,
+    nullptr, 0,
+    nullptr, 0,
+    elementNameTable_3_3, 252,
+    attributeNameTable_3_3, 546
+};
+
+}// namespace Assimp
+
+#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

+ 2 - 1
code/XFileExporter.cpp

@@ -43,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_X_EXPORTER
+
 #include "XFileExporter.h"
 #include "ConvertToLHProcess.h"
 #include "Bitmap.h"
 #include "BaseImporter.h"
 #include "fast_atof.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include <assimp/DefaultIOSystem.h>
 #include <ctime>
 #include <set>

+ 2 - 1
code/XFileImporter.cpp

@@ -237,8 +237,9 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
 // Creates the meshes for the given node.
 void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes)
 {
-    if( pMeshes.size() == 0)
+    if (pMeshes.empty()) {
         return;
+    }
 
     // create a mesh for each mesh-material combination in the source node
     std::vector<aiMesh*> meshes;

+ 4 - 7
code/XFileParser.cpp

@@ -466,15 +466,12 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
     pMesh->mPosFaces.resize( numPosFaces);
     for( unsigned int a = 0; a < numPosFaces; a++)
     {
-        unsigned int numIndices = ReadInt();
-        if( numIndices < 3) {
-            ThrowException( format() << "Invalid index count " << numIndices << " for face " << a << "." );
-        }
-
         // read indices
+        unsigned int numIndices = ReadInt();
         Face& face = pMesh->mPosFaces[a];
-        for( unsigned int b = 0; b < numIndices; b++)
-            face.mIndices.push_back( ReadInt());
+        for (unsigned int b = 0; b < numIndices; b++) {
+            face.mIndices.push_back( ReadInt() );
+        }
         TestForSeparator();
     }
 

+ 5 - 2
code/glTFExporter.cpp

@@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ByteSwapper.h"
 
 #include "SplitLargeMeshes.h"
-#include "SceneCombiner.h"
 
+#include <assimp/SceneCombiner.h>
 #include <assimp/version.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
@@ -185,8 +185,11 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
     unsigned int bytesPerComp = ComponentTypeSize(compType);
 
     size_t offset = buffer->byteLength;
+    // make sure offset is correctly byte-aligned, as required by spec
+    size_t padding = offset % bytesPerComp;
+    offset += padding;
     size_t length = count * numCompsOut * bytesPerComp;
-    buffer->Grow(length);
+    buffer->Grow(length + padding);
 
     // bufferView
     Ref<BufferView> bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));

+ 114 - 8
contrib/openddlparser/CMakeLists.txt

@@ -3,18 +3,40 @@ PROJECT( OpenDDL-Parser )
 SET ( OPENDDL_PARSER_VERSION_MAJOR 0 )
 SET ( OPENDDL_PARSER_VERSION_MINOR 1 )
 SET ( OPENDDL_PARSER_VERSION_PATCH 0 )
-SET ( OPENDDL_PARSER_VERSION ${CPPCORE_VERSION_MAJOR}.${CPPCORE_VERSION_MINOR}.${CPPCORE_VERSION_PATCH} )
+SET ( OPENDDL_PARSER_VERSION ${OPENDDL_PARSER_VERSION_MAJOR}.${OPENDDL_PARSER_VERSION_MINOR}.${OPENDDL_PARSER_VERSION_PATCH} )
 SET ( PROJECT_VERSION "${OPENDDL_PARSER_VERSION}" )
 
+option( DDL_USE_CPP11           "Set to ON to use C++11 features ( always on on windows )."                   ON )
+option( DDL_DEBUG_OUTPUT        "Set to ON to use output debug texts"                                         OFF )
+option( DDL_STATIC_LIBRARY		"Set to ON to build static libary of OpenDDL Parser."                         ON )
+option( COVERALLS               "Generate coveralls data"                                                     OFF )
+
+if ( DDL_USE_CPP11 )
+    if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
+        set( OPENDDL_CXXFLAGS -std=c++0x )
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+        set( OPENDDL_CXXFLAGS --std=c++11 )
+    endif()
+else( DDL_USE_CPP11 )
+    add_definitions( -DOPENDDL_NO_USE_CPP11 )
+endif( DDL_USE_CPP11)
+
 if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
     find_package(Threads)
 else()
     add_definitions( -D_CRT_SECURE_NO_WARNINGS )
 endif()
 
+if ( DDL_STATIC_LIBRARY )
+	add_definitions( -DOPENDDL_STATIC_LIBARY )
+endif()
+
 add_definitions( -DOPENDDLPARSER_BUILD )
-add_definitions( -DOPENDDL_NO_USE_CPP11 )
 add_definitions( -D_VARIADIC_MAX=10 )
+add_definitions( -DGTEST_HAS_PTHREAD=0 )
+if ( DDL_DEBUG_OUTPUT )
+    add_definitions( -DDDL_DEBUG_HEADER_NAME)
+endif()
 
 INCLUDE_DIRECTORIES(
     ./
@@ -24,9 +46,10 @@ INCLUDE_DIRECTORIES(
 )
 
 link_directories(
-    ./
+    ${CMAKE_HOME_DIRECTORY}/lib
 )
 
+set( CMAKE_MODULE_PATH  ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake )
 SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib )
 SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib )
 SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin )
@@ -40,18 +63,38 @@ if( WIN32 AND NOT CYGWIN )
   endif()
 elseif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
   # Update if necessary
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++0x")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS}")
 elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++11")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS} -Wwrite-strings")
+endif()
+
+if (COVERALLS)
+    include(Coveralls)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 endif()
 
+# Include the doc component.
+FIND_PACKAGE( doxygen )
+IF ( DOXYGEN_FOUND )
+    CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY )
+    ADD_CUSTOM_TARGET( doc ALL ${DOXYGEN_EXECUTABLE} doc/doxygenfile
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+        COMMENT "Generating API documentation with Doxygen" VERBATIM )
+ENDIF ( DOXYGEN_FOUND )
+
 SET ( openddl_parser_src
+    code/OpenDDLCommon.cpp
+    code/OpenDDLExport.cpp
     code/OpenDDLParser.cpp
+    code/OpenDDLStream.cpp
     code/DDLNode.cpp
     code/Value.cpp
+    include/openddlparser/OpenDDLCommon.h
+    include/openddlparser/OpenDDLExport.h
     include/openddlparser/OpenDDLParser.h
     include/openddlparser/OpenDDLParserUtils.h
-    include/openddlparser/OpenDDLCommon.h
+    include/openddlparser/OpenDDLStream.h
     include/openddlparser/DDLNode.h
     include/openddlparser/Value.h
     README.md
@@ -59,6 +102,69 @@ SET ( openddl_parser_src
  
 SOURCE_GROUP( code            FILES ${openddl_parser_src} )
 
-ADD_LIBRARY( openddl_parser SHARED
-    ${openddl_parser_src}
+if ( DDL_STATIC_LIBRARY )
+	ADD_LIBRARY( openddl_parser STATIC
+		${openddl_parser_src}
+	)
+else()
+	ADD_LIBRARY( openddl_parser SHARED
+		${openddl_parser_src}
+	)
+endif()
+
+SET ( GTEST_PATH contrib/gtest-1.7.0 )
+
+SET ( gtest_src
+    ${GTEST_PATH}/src/gtest-death-test.cc
+    ${GTEST_PATH}/src/gtest-filepath.cc
+    ${GTEST_PATH}/src/gtest-internal-inl.h
+    ${GTEST_PATH}/src/gtest-port.cc
+    ${GTEST_PATH}/src/gtest-printers.cc
+    ${GTEST_PATH}/src/gtest-test-part.cc
+    ${GTEST_PATH}/src/gtest-typed-test.cc
+    ${GTEST_PATH}/src/gtest.cc
+    ${GTEST_PATH}/src/gtest_main.cc
+)
+
+SET( openddl_parser_unittest_src  
+    test/UnitTestCommon.h
+    test/DDLNodeTest.cpp
+    test/OpenDDLCommonTest.cpp
+    test/OpenDDLExportTest.cpp
+    test/OpenDDLParserTest.cpp
+    test/OpenDDLParserUtilsTest.cpp
+    test/OpenDDLStreamTest.cpp
+    test/OpenDDLIntegrationTest.cpp
+    test/ValueTest.cpp
+    test/OpenDDLDefectsTest.cpp
+)
+
+SOURCE_GROUP( code  FILES ${openddl_parser_unittest_src} )
+SOURCE_GROUP( gtest FILES ${gtest_src} )
+
+ADD_EXECUTABLE( openddl_parser_unittest 
+    ${gtest_src}
+    ${openddl_parser_unittest_src}
+)
+
+target_link_libraries( openddl_parser_unittest openddl_parser ${CMAKE_THREAD_LIBS_INIT} )
+
+SET( openddl_parser_demo_src  
+    demo/main.cpp 
 )
+
+if (COVERALLS)
+    set(COVERAGE_SRCS     ${gtest_src} ${openddl_parser_unittest_src} )
+
+    # Create the coveralls target.
+    coveralls_setup(
+        "${COVERAGE_SRCS}" # The source files.
+        ON                 # If we should upload.
+        "${PROJECT_SOURCE_DIR}/cmake/") # (Optional) Alternate project cmake module path.
+endif()
+
+ADD_EXECUTABLE( openddl_parser_demo
+    ${openddl_parser_demo_src}
+) 
+
+target_link_libraries( openddl_parser_demo openddl_parser )

+ 3 - 0
contrib/openddlparser/CREDITS

@@ -12,5 +12,8 @@ Improvements value interface, serveral bugfixes.
 - Henry Read ( henrya2 ):
 Static build option, Interface improvements
 
+- (wise86-android)
+fix several mem-leaks
+
 - Paul Holland ( pkholland ):
 Bugfixes.

+ 2 - 2
contrib/openddlparser/README.md

@@ -11,7 +11,7 @@ Current coverity check status:
   <img alt="Coverity Scan Build Status"
        src="https://scan.coverity.com/projects/5606/badge.svg"/>
 </a>
-
+Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls)
 Get the source code
 ===================
 You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command:
@@ -25,7 +25,7 @@ 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-users the project files will be generated, for gcc-users the makefiles will be generated ).
+This command will generate a build environment for your preferred build tool ( 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

+ 14 - 6
contrib/openddlparser/code/DDLNode.cpp

@@ -68,8 +68,8 @@ DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx,
 }
 
 DDLNode::~DDLNode() {
-    releaseDataType<Property>( m_properties );
-    releaseDataType<Value>( m_value );
+    delete m_properties;
+    delete m_value;
     releaseReferencedNames( m_references );
 
     delete m_dtArrayList;
@@ -77,6 +77,9 @@ DDLNode::~DDLNode() {
     if( s_allocatedNodes[ m_idx ] == this ) {
         s_allocatedNodes[ m_idx ] = ddl_nullptr;
     }
+    for ( size_t i = 0; i<m_children.size(); i++ ){
+        delete m_children[ i ];
+    }
 }
 
 void DDLNode::attachParent( DDLNode *parent ) {
@@ -91,9 +94,8 @@ void DDLNode::attachParent( DDLNode *parent ) {
 }
 
 void DDLNode::detachParent() {
-    if( m_parent ) {
-        std::vector<DDLNode*>::iterator it;
-        it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this );
+    if( ddl_nullptr != m_parent ) {
+        DDLNodeIt it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this );
         if( m_parent->m_children.end() != it ) {
             m_parent->m_children.erase( it );
         }
@@ -126,6 +128,8 @@ const std::string &DDLNode::getName() const {
 }
 
 void DDLNode::setProperties( Property *prop ) {
+    if(m_properties!=ddl_nullptr)
+        delete m_properties;
     m_properties = prop;
 }
 
@@ -187,6 +191,10 @@ Reference *DDLNode::getReferences() const {
     return m_references;
 }
 
+void DDLNode::dump(IOStreamBase &stream) {
+    // Todo!    
+}
+
 DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLNode *parent ) {
     const size_t idx( s_allocatedNodes.size() );
     DDLNode *node = new DDLNode( type, name, idx, parent );
@@ -197,7 +205,7 @@ DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLN
 
 void DDLNode::releaseNodes() {
     if( s_allocatedNodes.size() > 0 ) {
-        for( DllNodeList::iterator it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) {
+        for( DDLNodeIt it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) {
             if( *it ) {
                 delete *it;
             }

+ 35 - 9
contrib/openddlparser/code/OpenDDLCommon.cpp

@@ -22,6 +22,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 -----------------------------------------------------------------------------------------------*/
 #include <openddlparser/OpenDDLCommon.h>
 #include <openddlparser/DDLNode.h>
+#include <openddlparser/Value.h>
 
 BEGIN_ODDLPARSER_NS
 
@@ -84,7 +85,14 @@ Name::~Name() {
     m_id = ddl_nullptr;
 }
 
-Reference::Reference()
+Name::Name( const Name &name ){
+    m_type=name.m_type;
+    m_id=new Text(name.m_id->m_buffer,name.m_id->m_len);
+}
+
+
+
+    Reference::Reference()
 : m_numRefs( 0 )
 , m_referencedName( ddl_nullptr ) {
     // empty
@@ -96,8 +104,16 @@ Reference::Reference( size_t numrefs, Name **names )
     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;
+            m_referencedName[ i ] = names[i];
+        }
+    }
+}
+Reference::Reference(const Reference &ref) {
+    m_numRefs=ref.m_numRefs;
+    if(m_numRefs!=0){
+        m_referencedName = new Name*[m_numRefs];
+        for ( size_t i = 0; i < m_numRefs; i++ ) {
+            m_referencedName[i] = new Name(*ref.m_referencedName[i]);
         }
     }
 }
@@ -107,6 +123,7 @@ Reference::~Reference() {
         delete m_referencedName[ i ];
     }
     m_numRefs = 0;
+    delete [] m_referencedName;
     m_referencedName = ddl_nullptr;
 }
 
@@ -135,21 +152,30 @@ Property::Property( Text *id )
 }
 
 Property::~Property() {
-    m_key = ddl_nullptr;
-    m_value = ddl_nullptr;
-    m_ref = ddl_nullptr;;
-    m_next = ddl_nullptr;;
+    delete m_key;
+    if(m_value!=ddl_nullptr)
+        delete m_value;
+    if(m_ref!=ddl_nullptr)
+        delete(m_ref);
+    if(m_next!=ddl_nullptr)
+        delete m_next;
 }
 
 DataArrayList::DataArrayList()
 : m_numItems( 0 )
 , m_dataList( ddl_nullptr )
-, m_next( ddl_nullptr ) {
+, m_next( ddl_nullptr )
+, m_refs(ddl_nullptr)
+, m_numRefs(0){
     // empty
 }
 
 DataArrayList::~DataArrayList() {
-    // empty
+    delete m_dataList;
+    if(m_next!=ddl_nullptr)
+        delete m_next;
+    if(m_refs!=ddl_nullptr)
+        delete m_refs;
 }
 
 size_t DataArrayList::size() {

+ 1 - 55
contrib/openddlparser/code/OpenDDLExport.cpp

@@ -29,60 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 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;
@@ -280,7 +226,7 @@ bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std:
         statement += "[";
         char buffer[ 256 ];
         ::memset( buffer, '\0', 256 * sizeof( char ) );
-        sprintf( buffer, "%d", int(numItems) );
+        sprintf( buffer, "%d", static_cast<int>( numItems ) );
         statement += buffer;
         statement += "]";
     }

+ 80 - 65
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -36,7 +36,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
-static const char *Version = "0.3.0";
+static const char *Version = "0.4.0";
 
 namespace Grammar {
     static const char *OpenBracketToken   = "{";
@@ -49,7 +49,7 @@ namespace Grammar {
     static const char *BoolFalse          = "false";
     static const char *CommaSeparator     = ",";
 
-    static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = {
+    static const char *PrimitiveTypeToken[ Value::ddl_types_max ] = {
         "bool",
         "int8",
         "int16",
@@ -74,8 +74,8 @@ const char *getTypeToken( Value::ValueType  type ) {
 static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) {
     std::stringstream stream;
     stream << "Invalid token \"" << *in << "\"" << " expected \"" << exp << "\"" << std::endl;
-    std::string full(in);
-    std::string part(full.substr(0,50));
+    std::string full( in );
+    std::string part( full.substr( 0, 50 ) );
     stream << part;
     callback( ddl_error_msg, stream.str() );
 }
@@ -85,6 +85,7 @@ static bool isIntegerType( Value::ValueType integerType ) {
             integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) {
         return false;
     }
+    
     return true;
 }
 
@@ -105,7 +106,7 @@ static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) {
     const std::string type( id->m_buffer );
     DDLNode *parent( parser->top() );
     DDLNode *node = DDLNode::create( type, "", parent );
-
+    
     return node;
 }
 
@@ -193,10 +194,11 @@ size_t OpenDDLParser::getBufferSize() const {
 void OpenDDLParser::clear() {
     m_buffer.resize( 0 );
     if( ddl_nullptr != m_context ) {
-        m_context->m_root = ddl_nullptr;
+        delete m_context;
+        m_context=ddl_nullptr;
     }
 
-    DDLNode::releaseNodes();
+//    DDLNode::releaseNodes();
 }
 
 bool OpenDDLParser::parse() {
@@ -212,11 +214,11 @@ bool OpenDDLParser::parse() {
 
     // do the main parsing
     char *current( &m_buffer[ 0 ] );
-    char *end( &m_buffer[ m_buffer.size() - 1 ] + 1 );
+    char *end( &m_buffer[m_buffer.size() - 1 ] + 1 );
     size_t pos( current - &m_buffer[ 0 ] );
     while( pos < m_buffer.size() ) {
         current = parseNextNode( current, end );
-        if(current==ddl_nullptr) {
+        if ( current == ddl_nullptr ) {
             return false;
         }
         pos = current - &m_buffer[ 0 ];
@@ -245,7 +247,7 @@ static void dumpId( Identifier *id ) {
     if( ddl_nullptr != id ) {
         if ( ddl_nullptr != id->m_text.m_buffer ) {
             std::cout << id->m_text.m_buffer << std::endl;
-	}
+	    }
     }
 }
 #endif
@@ -271,14 +273,17 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
         } else {
             std::cerr << "nullptr returned by creating DDLNode." << std::endl;
         }
+        delete id;
 
 		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 );
+            delete name;
         }
 
+
 		Property *first(ddl_nullptr);
 		in = lookForNextToken(in, end);
 		if (*in == Grammar::OpenPropertyToken[0]) {
@@ -303,7 +308,7 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
 					prev = prop;
 				}
 			}
-			in++;
+			++in;
 		}
 
 		// set the properties
@@ -322,17 +327,17 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) {
 
     bool error( false );
     in = lookForNextToken( in, end );
-    if( *in == '{' ) {
+    if( *in == *Grammar::OpenBracketToken) {
         // loop over all children ( data and nodes )
         do {
             in = parseStructureBody( in, end, error );
             if(in == ddl_nullptr){
                 return ddl_nullptr;
             }
-        } while ( *in != '}' );
-        in++;
+        } while ( *in != *Grammar::CloseBracketToken);
+        ++in;
     } else {
-        in++;
+        ++in;
         logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback );
         error = true;
         return ddl_nullptr;
@@ -373,7 +378,7 @@ static void setNodeDataArrayList( DDLNode *currentNode, DataArrayList *dtArrayLi
 
 char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) {
     if( !isNumeric( *in ) && !isCharacter( *in ) ) {
-        in++;
+        ++in;
     }
 
     in = lookForNextToken( in, end );
@@ -431,7 +436,6 @@ DDLNode *OpenDDLParser::popNode() {
 
     DDLNode *topNode( top() );
     m_stack.pop_back();
-
     return topNode;
 }
 
@@ -467,7 +471,14 @@ void OpenDDLParser::normalizeBuffer( std::vector<char> &buffer) {
     for( size_t readIdx = 0; readIdx<len; ++readIdx ) {
         char *c( &buffer[readIdx] );
         // check for a comment
-        if( !isComment<char>( c, end ) && !isNewLine( *c ) ) {
+        if (isCommentOpenTag(c, end)) {
+            ++readIdx;
+            while (!isCommentCloseTag(&buffer[readIdx], end)) {
+                ++readIdx;
+            }
+            ++readIdx;
+            ++readIdx;
+        } else if( !isComment<char>( c, end ) && !isNewLine( *c ) ) {
             newBuffer.push_back( buffer[ readIdx ] );
         } else {
             if( isComment<char>( c, end ) ) {
@@ -529,14 +540,17 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) {
     // get size of id
     size_t idLen( 0 );
     char *start( in );
-    while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] && *in != '$' ) {
+    while( !isSeparator( *in ) && 
+            !isNewLine( *in ) && ( in != end ) && 
+            *in != Grammar::OpenPropertyToken[ 0 ] &&
+            *in != Grammar::ClosePropertyToken[ 0 ] && 
+            *in != '$' ) {
         ++in;
         ++idLen;
     }
 
     const size_t len( idLen );
-    Text *newId = new Text( start, len );
-    *id = newId;
+    *id = new Text( start, len );
 
     return in;
 }
@@ -552,7 +566,7 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy
     for( unsigned int i = 0; i < Value::ddl_types_max; i++ ) {
         prim_len = strlen( Grammar::PrimitiveTypeToken[ i ] );
         if( 0 == strncmp( in, Grammar::PrimitiveTypeToken[ i ], prim_len ) ) {
-            type = ( Value::ValueType ) i;
+            type = static_cast<Value::ValueType>( i );
             break;
         }
     }
@@ -567,14 +581,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy
     bool ok( true );
     if( *in == Grammar::OpenArrayToken[ 0 ] ) {
         ok = false;
-        in++;
+        ++in;
         char *start( in );
         while ( in != end ) {
-            in++;
+            ++in;
             if( *in == Grammar::CloseArrayToken[ 0 ] ) {
                 len = ::atoi( start );
                 ok = true;
-                in++;
+                ++in;
                 break;
             }
         }
@@ -623,10 +637,10 @@ char *OpenDDLParser::parseBooleanLiteral( char *in, char *end, Value **boolean )
     char *start( in );
     size_t len( 0 );
     while( !isSeparator( *in ) && in != end ) {
-        in++;
-        len++;
+        ++in;
+        ++len;
     }
-    len++;
+    ++len;
     int res = ::strncmp( Grammar::BoolTrue, start, strlen( Grammar::BoolTrue ) );
     if( 0 != res ) {
         res = ::strncmp( Grammar::BoolFalse, start, strlen( Grammar::BoolFalse ) );
@@ -657,7 +671,7 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer,
     in = lookForNextToken( in, end );
     char *start( in );
     while( !isSeparator( *in ) && in != end ) {
-        in++;
+        ++in;
     }
 
     if( isNumeric( *start ) ) {
@@ -671,29 +685,29 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer,
         *integer = ValueAllocator::allocPrimData( integerType );
         switch( integerType ) {
             case Value::ddl_int8:
-                    ( *integer )->setInt8( (int8) value );
-                    break;
+                ( *integer )->setInt8( (int8) value );
+                break;
             case Value::ddl_int16:
-                    ( *integer )->setInt16( ( int16 ) value );
-                    break;
+                ( *integer )->setInt16( ( int16 ) value );
+                break;
             case Value::ddl_int32:
-                    ( *integer )->setInt32( ( int32 ) value );
-                    break;
+                ( *integer )->setInt32( ( int32 ) value );
+                break;
             case Value::ddl_int64:
-                    ( *integer )->setInt64( ( int64 ) value );
-                    break;
+                ( *integer )->setInt64( ( int64 ) value );
+                break;
             case Value::ddl_unsigned_int8:
-                    ( *integer )->setUnsignedInt8( (uint8) uvalue );
-                    break;
+                ( *integer )->setUnsignedInt8( (uint8) uvalue );
+                break;
             case Value::ddl_unsigned_int16:
-                    ( *integer )->setUnsignedInt16( ( uint16 ) uvalue );
-                    break;
+                ( *integer )->setUnsignedInt16( ( uint16 ) uvalue );
+                break;
             case Value::ddl_unsigned_int32:
-                    ( *integer )->setUnsignedInt32( ( uint32 ) uvalue );
-                    break;
+                ( *integer )->setUnsignedInt32( ( uint32 ) uvalue );
+                break;
             case Value::ddl_unsigned_int64:
-                    ( *integer )->setUnsignedInt64( ( uint64 ) uvalue );
-                    break;
+                ( *integer )->setUnsignedInt64( ( uint64 ) uvalue );
+                break;
             default:
                 break;
         }
@@ -711,7 +725,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating
     in = lookForNextToken( in, end );
     char *start( in );
     while( !isSeparator( *in ) && in != end ) {
-        in++;
+        ++in;
     }
 
     // parse the float value
@@ -732,8 +746,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating
     }
 
     if( ok ) {
-        if(floatType == Value::ddl_double)
-        {
+        if ( floatType == Value::ddl_double ) {
             const double value( atof( start ) );
             *floating = ValueAllocator::allocPrimData( Value::ddl_double );
             ( *floating )->setDouble( value );
@@ -757,17 +770,17 @@ char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData
     size_t len( 0 );
     char *start( in );
     if( *start == '\"' ) {
-        start++;
-        in++;
+        ++start;
+        ++in;
         while( *in != '\"' && in != end ) {
-            in++;
-            len++;
+            ++in;
+            ++len;
         }
 
         *stringData = ValueAllocator::allocPrimData( Value::ddl_string, len );
         ::strncpy( ( char* ) ( *stringData )->m_data, start, len );
         ( *stringData )->m_data[len] = '\0';
-        in++;
+        ++in;
     }
 
     return in;
@@ -791,12 +804,12 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) {
         return in;
     }
 
-    in++;
+    ++in;
     if( *in != 'x' && *in != 'X' ) {
         return in;
     }
 
-    in++;
+    ++in;
     bool ok( true );
     char *start( in );
     int pos( 0 );
@@ -805,8 +818,8 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) {
             ok = false;
             break;
         }
-        pos++;
-        in++;
+        ++pos;
+        ++in;
     }
 
     if( !ok ) {
@@ -816,9 +829,9 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) {
     int value( 0 );
     while( pos > 0 ) {
         int v = hex2Decimal( *start );
-        pos--;
+        --pos;
         value = ( value << 4 ) | v;
-        start++;
+        ++start;
     }
 
     *data = ValueAllocator::allocPrimData( Value::ddl_unsigned_int64 );
@@ -841,7 +854,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) {
     if( ddl_nullptr != id ) {
         in = lookForNextToken( in, end );
         if( *in == '=' ) {
-            in++;
+            ++in;
             in = getNextToken( in, end );
             Value *primData( ddl_nullptr );
             if( isInteger( in, end ) ) {
@@ -862,6 +875,8 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) {
                     ( *prop )->m_ref = ref;
                 }
             }
+        } else {
+            delete id;
         }
     }
 
@@ -878,7 +893,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type,
 
     in = lookForNextToken( in, end );
     if( *in == '{' ) {
-        in++;
+        ++in;
         Value *current( ddl_nullptr ), *prev( ddl_nullptr );
         while( '}' != *in ) {
             current = ddl_nullptr;
@@ -934,7 +949,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type,
                     prev->setNext( current );
                     prev = current;
                 }
-                numValues++;
+                ++numValues;
             }
 
             in = getNextSeparator( in, end );
@@ -942,7 +957,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type,
                 break;
             }
         }
-        in++;
+        ++in;
     }
 
     return in;
@@ -972,7 +987,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty
 
     in = lookForNextToken( in, end );
     if( *in == Grammar::OpenBracketToken[ 0 ] ) {
-        in++;
+        ++in;
         Value *currentValue( ddl_nullptr );
         Reference *refs( ddl_nullptr );
         DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr );
@@ -995,7 +1010,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty
             }
         } while( Grammar::CommaSeparator[ 0 ] == *in && in != end );
         in = lookForNextToken( in, end );
-        in++;
+        ++in;
     }
 
     return in;

+ 96 - 0
contrib/openddlparser/code/OpenDDLStream.cpp

@@ -0,0 +1,96 @@
+/*-----------------------------------------------------------------------------------------------
+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 <openddlparser/OpenDDLStream.h>
+
+BEGIN_ODDLPARSER_NS
+
+StreamFormatterBase::StreamFormatterBase() {
+    // empty
+}
+
+StreamFormatterBase::~StreamFormatterBase() {
+    // empty
+}
+
+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;
+}
+
+bool IOStreamBase::isOpen() const {
+    return ( ddl_nullptr != m_file );
+}
+
+size_t IOStreamBase::read( size_t sizeToRead, std::string &statement ) {
+    if (ddl_nullptr == m_file) {
+        return 0;
+    }
+    
+    statement.resize(sizeToRead);
+    const size_t readBytes = ::fread( &statement[0], 1, sizeToRead, m_file );
+
+    return readBytes;
+}
+
+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);
+}
+
+END_ODDLPARSER_NS

+ 17 - 18
contrib/openddlparser/code/Value.cpp

@@ -110,7 +110,17 @@ Value::Value( ValueType type )
 }
 
 Value::~Value() {
-    // empty
+    if(m_data!=ddl_nullptr) {
+        if (m_type == ddl_ref ) {
+            Reference *tmp = (Reference *) m_data;
+            if (tmp != ddl_nullptr)
+                delete tmp;
+        }else
+            delete[] m_data;
+
+    }
+    if(m_next!=ddl_nullptr)
+        delete m_next;
 }
 
 void Value::setBool( bool value ) {
@@ -273,13 +283,7 @@ void Value::setRef( Reference *ref ) {
                 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 );
-            }
+            m_data = (unsigned char*) new Reference(*ref);
         }
     }
 }
@@ -290,7 +294,7 @@ Reference *Value::getRef() const {
     return (Reference*) m_data;
 }
 
-void Value::dump() {
+void Value::dump( IOStreamBase &stream ) {
     switch( m_type ) {
         case ddl_none:
             std::cout << "None" << std::endl;
@@ -350,7 +354,7 @@ Value *Value::getNext() const {
     return m_next;
 }
 
-size_t Value::size(){
+size_t Value::size() const{
     size_t result=1;
     Value *n=m_next;
     while( n!=ddl_nullptr) {
@@ -366,7 +370,6 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
     }
 
     Value *data = new Value( type );
-    data->m_type = type;
     switch( type ) {
         case Value::ddl_bool:
             data->m_size = sizeof( bool );
@@ -405,10 +408,10 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
             data->m_size = sizeof( double );
             break;
         case Value::ddl_string:
-            data->m_size = sizeof( char );
+            data->m_size = sizeof( char )*(len+1);
             break;
         case Value::ddl_ref:
-            data->m_size = sizeof( char );
+            data->m_size = 0;
             break;
         case Value::ddl_none:
         case Value::ddl_types_max:
@@ -417,12 +420,8 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
     }
 
     if( data->m_size ) {
-        size_t len1( len );
-        if( Value::ddl_string == type ) {
-            len1++;
-        }
-        data->m_size *= len1;
         data->m_data = new unsigned char[ data->m_size ];
+        ::memset(data->m_data,0,data->m_size);
     }
 
     return data;

+ 19 - 10
contrib/openddlparser/include/openddlparser/DDLNode.h

@@ -29,6 +29,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
+// Forward declarations
+class IOStreamBase;
 class Value;
 class OpenDDLParser;
 
@@ -53,6 +55,9 @@ public:
     /// @brief  The child-node-list type.
     typedef std::vector<DDLNode*> DllNodeList;
 
+    /// @brief  The child-node-list iterator.
+    typedef std::vector<DDLNode*>::iterator DDLNodeIt;
+
 public:
     ///	@brief  The class destructor.
     ~DDLNode();
@@ -81,7 +86,7 @@ public:
     const std::string &getType() const;
 
     /// Set the name of the DDLNode instance.
-    /// @param  type    [in] The name.
+    /// @param  name        [in] The name.
     void setName( const std::string &name );
 
     /// @brief  Returns the name of the DDLNode instance.
@@ -89,7 +94,7 @@ public:
     const std::string &getName() const;
 
     /// @brief  Set a new property set.
-    ///	@param  prop    [in] The first element of the property set.
+    ///	@param  prop        [in] The first element of the property set.
     void setProperties( Property *prop );
 
     ///	@brief  Returns the first element of the assigned property set.
@@ -97,7 +102,7 @@ public:
     Property *getProperties() const;
 
     ///	@brief  Looks for a given property.
-    /// @param  name    [in] The name for the property to look for.
+    /// @param  name        [in] The name for the property to look for.
     /// @return true, if a corresponding property is assigned to the node, false if not.
     bool hasProperty( const std::string &name );
 
@@ -106,12 +111,12 @@ public:
     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.
+    /// @param  name        [in] The name for the property to look for.
     /// @return The property or ddl_nullptr if no property was found.
     Property *findPropertyByName( const std::string &name );
     
     /// @brief  Set a new value set.
-    /// @param  val     [in] The first value instance of the value set.
+    /// @param  val         [in] The first value instance of the value set.
     void setValue( Value *val );
 
     ///	@brief  Returns the first element of the assigned value set.
@@ -119,7 +124,7 @@ public:
     Value *getValue() const;
 
     /// @brief  Set a new DataArrayList.
-    /// @param  val     [in] The DataArrayList instance.
+    /// @param  dtArrayList [in] The DataArrayList instance.
     void setDataArrayList( DataArrayList *dtArrayList );
 
     ///	@brief  Returns the DataArrayList.
@@ -127,17 +132,21 @@ public:
     DataArrayList *getDataArrayList() const;
 
     /// @brief  Set a new Reference set.
-    /// @param  val     [in] The first value instance of the Reference set.
+    /// @param  refs        [in] The first value instance of the Reference set.
     void setReferences( Reference  *refs );
 
     ///	@brief  Returns the first element of the assigned Reference set.
     ///	@return The first property of the assigned Reference set.
     Reference *getReferences() const;
 
+    /// @brief  Will dump the node into the stream.
+    /// @param  stream      [in] The stream to write to.
+    void dump(IOStreamBase &stream);
+
     ///	@brief  The creation method.
-    /// @param  type    [in] The DDLNode type.
-    ///	@param  name    [in] The name for the new DDLNode instance.
-    /// @param  parent  [in] The parent node instance or ddl_nullptr if no parent node is there.
+    /// @param  type        [in] The DDLNode type.
+    ///	@param  name        [in] The name for the new DDLNode instance.
+    /// @param  parent      [in] The parent node instance or ddl_nullptr if no parent node is there.
     /// @return The new created node instance.
     static DDLNode *create( const std::string &type, const std::string &name, DDLNode *parent = ddl_nullptr );
 

+ 3 - 4
contrib/openddlparser/include/openddlparser/OpenDDLCommon.h

@@ -148,12 +148,12 @@ struct DLL_ODDLPARSER_EXPORT Name {
     ///	@param  type    [in] The name type.
     ///	@param  id      [in] The id.
     Name( NameType type, Text *id );
-
+    Name( const Name &name );
     ///	@brief  The destructor.
     ~Name();
 
 private:
-    Name( const Name & ) ddl_no_copy;
+
     Name &operator = ( const Name& ) ddl_no_copy;
 };
 
@@ -164,7 +164,7 @@ struct DLL_ODDLPARSER_EXPORT Reference {
 
     ///	@brief  The default constructor.
     Reference();
-
+    Reference( const Reference &ref );
     ///	@brief  The constructor with an array of ref names.
     /// @param  numrefs     [in] The number of ref names.
     /// @param  names       [in] The ref names.
@@ -178,7 +178,6 @@ struct DLL_ODDLPARSER_EXPORT Reference {
     size_t sizeInBytes();
 
 private:
-    Reference( const Reference & ) ddl_no_copy;
     Reference &operator = ( const Reference & ) ddl_no_copy;
 };
 

+ 3 - 27
contrib/openddlparser/include/openddlparser/OpenDDLExport.h

@@ -23,37 +23,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include <openddlparser/OpenDDLCommon.h>
+#include <openddlparser/OpenDDLStream.h>
 #include <openddlparser/Value.h>
 
 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;
-};
+// Forward declarations
+class IOStreamBase;
 
 //-------------------------------------------------------------------------------------------------
 ///

+ 11 - 1
contrib/openddlparser/include/openddlparser/OpenDDLParser.h

@@ -39,6 +39,16 @@ struct Identifier;
 struct Reference;
 struct Property;
 
+template<class T>
+inline
+bool isEmbeddedCommentOpenTag( T *in, T *end ) {
+    if ( in == '/' && in+1 == '*' ) {
+        return true;
+    }
+
+    return false;
+}
+
 ///	@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.
@@ -47,7 +57,7 @@ struct Property;
 template<class T>
 inline
 T *lookForNextToken( T *in, T *end ) {
-    while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
+    while( ( in != end ) && ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) ) {
         in++;
     }
     return in;

+ 36 - 8
contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h

@@ -84,7 +84,7 @@ static const unsigned char chartype_table[ 256 ] = {
 template<class T>
 inline
 bool isNumeric( const T in ) {
-	return ( chartype_table[ static_cast<int>( in ) ] == 1 );
+    return ( chartype_table[ static_cast<size_t>( in ) ] == 1 );
 }
 
 template<class T>
@@ -98,7 +98,7 @@ inline
 bool isInteger( T *in, T *end ) {
     if( in != end ) {
         if( *in == '-' ) {
-            in++;
+            ++in;
         }
     }
 
@@ -108,7 +108,7 @@ bool isInteger( T *in, T *end ) {
         if( !result ) {
             break;
         }
-        in++;
+        ++in;
     }
 
     return result;
@@ -119,7 +119,7 @@ inline
 bool isFloat( T *in, T *end ) {
     if( in != end ) {
         if( *in == '-' ) {
-            in++;
+            ++in;
         }
     }
 
@@ -134,12 +134,12 @@ bool isFloat( T *in, T *end ) {
         if( !result ) {
             return false;
         }
-        in++;
+        ++in;
     }
 
     // check for 1<.>0f
     if( *in == '.' ) {
-        in++;
+        ++in;
     } else {
         return false;
     }
@@ -150,7 +150,7 @@ bool isFloat( T *in, T *end ) {
         if( !result ) {
             return false;
         }
-        in++;
+        ++in;
     }
 
     return result;
@@ -208,7 +208,7 @@ template<class T>
 inline
 static T *getNextSeparator( T *in, T *end ) {
     while( !isSeparator( *in ) || in == end ) {
-        in++;
+        ++in;
     }
     return in;
 }
@@ -250,5 +250,33 @@ bool isComment( T *in, T *end ) {
     return false;
 }
 
+template<class T>
+inline
+bool isCommentOpenTag(T *in, T *end ) {
+    if (*in == '/') {
+        if (in + 1 != end) {
+            if (*(in + 1) == '*') {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+template<class T>
+inline
+bool isCommentCloseTag(T *in, T *end) {
+    if (*in == '*') {
+        if (in + 1 != end) {
+            if (*(in + 1) == '/') {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 END_ODDLPARSER_NS
 

+ 89 - 0
contrib/openddlparser/include/openddlparser/OpenDDLStream.h

@@ -0,0 +1,89 @@
+/*-----------------------------------------------------------------------------------------------
+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 <openddlparser/OpenDDLCommon.h>
+
+BEGIN_ODDLPARSER_NS
+
+//-------------------------------------------------------------------------------------------------
+/// @ingroup    IOStreamBase
+///	@brief      This class represents the stream to write out.
+//-------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT StreamFormatterBase {
+public:
+    /// @brief  The class constructor.
+    StreamFormatterBase();
+
+    /// @brief  The class destructor, virtual.
+    virtual ~StreamFormatterBase();
+
+    /// @brief  Will format the sring and return the new formatted result.
+    /// @param  statement   [in] The string to reformat.
+    /// @return The reformatted result.
+    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:
+    /// @brief  The class constructor with the formatter.
+    /// @param  formatter   [in] The formatter to use.
+    explicit IOStreamBase(StreamFormatterBase *formatter = ddl_nullptr);
+
+    /// @brief  The class destructor, virtual.
+    virtual ~IOStreamBase();
+
+    /// @brief  Will open the stream.
+    /// @param  name        [in] The name for the stream.
+    /// @return true, if the stream was opened successfully, false if not.
+    virtual bool open(const std::string &name);
+
+    /// @brief  Will close the stream.
+    /// @return true, if the stream was closed successfully, false if not.
+    virtual bool close();
+
+    /// @brief  Returns true, if the stream is open.
+    /// @return true, if the stream is open, false if not.
+    virtual bool isOpen() const;
+
+    /// @brief  Will read a string from the stream.
+    /// @param  sizeToRead  [in] The size to read in bytes.
+    /// @param  statement   [out] The read statements.
+    /// @return The bytes read from the stream.
+    virtual size_t read( size_t sizeToRead, std::string &statement );
+
+    /// @brief  Will write a string into the stream.
+    /// @param  statement  [in] The string to write.
+    /// @return The bytes written into the stream.
+    virtual size_t write(const std::string &statement);
+
+private:
+    StreamFormatterBase *m_formatter;
+    FILE *m_file;
+};
+
+END_ODDLPARSER_NS

+ 7 - 3
contrib/openddlparser/include/openddlparser/Value.h

@@ -28,8 +28,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
+// Forward declarations
 struct ValueAllocator;
 
+class IOStreamBase;
+
 ///------------------------------------------------------------------------------------------------
 ///	@brief  This class implements a value.
 ///
@@ -213,7 +216,7 @@ public:
     double getDouble() const;
 
     ///	@brief  Assigns a std::string to the value.
-    /// @param  value       [in] The value.
+    /// @param  str         [in] The value.
     void setString( const std::string &str );
 
     ///	@brief  Returns the std::string value.
@@ -229,7 +232,8 @@ public:
     Reference *getRef() const;
 
     ///	@brief  Dumps the value.
-    void dump();
+    /// @param  stream  [in] The stream to write in.
+    void dump( IOStreamBase &stream );
 
     ///	@brief  Assigns the next value.
     ///	@param  next        [n] The next value.
@@ -241,7 +245,7 @@ public:
 
     /// @brief  Gets the length of the array.
     /// @return The number of items in the array.
-    size_t size();
+    size_t size() const;
 
     ValueType m_type;
     size_t m_size;

+ 0 - 2
code/SceneCombiner.h → include/assimp/SceneCombiner.h

@@ -143,7 +143,6 @@ struct NodeAttachmentInfo
  */
 #define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10
 
-
 typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
 
 // ---------------------------------------------------------------------------
@@ -153,7 +152,6 @@ struct BoneWithHash : public std::pair<uint32_t,aiString*>  {
     std::vector<BoneSrcIndex> pSrcBones;
 };
 
-
 // ---------------------------------------------------------------------------
 /** @brief Utility for SceneCombiner
  */

+ 10 - 3
include/assimp/config.h.in

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2016, assimp team
+Copyright (c) 2006-2017, assimp team
 
 All rights reserved.
 
@@ -632,8 +632,15 @@ enum aiComponent
 #define AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES \
     "IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES"
 
-
-
+// ---------------------------------------------------------------------------
+/** @brief Set whether the fbx importer will search for embedded loaded textures, where no embedded texture data is provided.
+*
+* The default value is false (0)
+* Property type: bool
+*/
+#define AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES \
+	"IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES"
+	
 // ---------------------------------------------------------------------------
 /** @brief  Set the vertex animation keyframe to be imported
  *

+ 16 - 4
include/assimp/material.inl

@@ -48,6 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_MATERIAL_INL_INC
 #define AI_MATERIAL_INL_INC
 
+// ---------------------------------------------------------------------------
+inline aiPropertyTypeInfo ai_real_to_property_type_info(float)
+{
+	return aiPTI_Float;
+}
+
+inline aiPropertyTypeInfo ai_real_to_property_type_info(double)
+{
+	return aiPTI_Double;
+}
+// ---------------------------------------------------------------------------
+
 //! @cond never
 
 // ---------------------------------------------------------------------------
@@ -223,7 +235,7 @@ inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput,
 {
     return AddBinaryProperty((const void*)pInput,
         pNumValues * sizeof(aiUVTransform),
-        pKey,type,index,aiPTI_Float); //TODO could be Double ...
+        pKey,type,index,ai_real_to_property_type_info(pInput->mRotation));
 }
 
 // ---------------------------------------------------------------------------
@@ -235,7 +247,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput,
 {
     return AddBinaryProperty((const void*)pInput,
         pNumValues * sizeof(aiColor4D),
-        pKey,type,index,aiPTI_Float); //TODO could be Double ...
+        pKey,type,index,ai_real_to_property_type_info(pInput->a));
 }
 
 // ---------------------------------------------------------------------------
@@ -247,7 +259,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput,
 {
     return AddBinaryProperty((const void*)pInput,
         pNumValues * sizeof(aiColor3D),
-        pKey,type,index,aiPTI_Float); //TODO could be Double ...
+        pKey,type,index,ai_real_to_property_type_info(pInput->b));
 }
 
 // ---------------------------------------------------------------------------
@@ -259,7 +271,7 @@ inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput,
 {
     return AddBinaryProperty((const void*)pInput,
         pNumValues * sizeof(aiVector3D),
-        pKey,type,index,aiPTI_Float); //TODO could be Double ...
+        pKey,type,index,ai_real_to_property_type_info(pInput->x));
 }
 
 // ---------------------------------------------------------------------------

+ 94 - 94
port/PyAssimp/README.md

@@ -1,94 +1,94 @@
-PyAssimp Readme
-===============
-
-A simple Python wrapper for Assimp using `ctypes` to access the library.
-Requires Python >= 2.6.
-
-Python 3 support is mostly here, but not well tested.
-
-Note that pyassimp is not complete. Many ASSIMP features are missing.
-
-USAGE
------
-
-### Complete example: 3D viewer
-
-`pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D
-model using a shader-based OpenGL pipeline.
-
-![Screenshot](3d_viewer_screenshot.png)
-
-To use it, from within `/port/PyAssimp`:
-
-```
-$ cd scripts
-$ python ./3D-viewer <path to your model>
-```
-
-You can use this code as starting point in your applications.
-
-### Writing your own code
-
-To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`,
-which illustrates the basic usage. All Assimp data structures are wrapped using
-`ctypes`. All the data+length fields in Assimp's data structures (such as
-`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python
-lists, so you can call `len()` on them to get their respective size and access
-members using `[]`.
-
-For example, to load a file named `hello.3ds` and print the first
-vertex of the first mesh, you would do (proper error handling
-substituted by assertions ...):
-
-```python
-
-from pyassimp import *
-scene = load('hello.3ds')
-
-assert len(scene.meshes)
-mesh = scene.meshes[0]
-
-assert len(mesh.vertices)
-print(mesh.vertices[0])
-
-# don't forget this one, or you will leak!
-release(scene)
-
-```
-
-Another example to list the 'top nodes' in a
-scene:
-
-```python
-
-from pyassimp import *
-scene = load('hello.3ds')
-
-for c in scene.rootnode.children:
-    print(str(c))
-
-release(scene)
-
-```
-
-INSTALL
--------
-
-Install `pyassimp` by running:
-
-```
-$ python setup.py install
-```
-
-PyAssimp requires a assimp dynamic library (`DLL` on windows,
-`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories 
-are:
-
-- the current directory
-- on linux additionally: `/usr/lib`, `/usr/local/lib`,
-  `/usr/lib/x86_64-linux-gnu`
-
-To build that library, refer to the Assimp master `INSTALL`
-instructions. To look in more places, edit `./pyassimp/helper.py`.
-There's an `additional_dirs` list waiting for your entries.
-
+PyAssimp Readme
+===============
+
+A simple Python wrapper for Assimp using `ctypes` to access the library.
+Requires Python >= 2.6.
+
+Python 3 support is mostly here, but not well tested.
+
+Note that pyassimp is not complete. Many ASSIMP features are missing.
+
+USAGE
+-----
+
+### Complete example: 3D viewer
+
+`pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D
+model using a shader-based OpenGL pipeline.
+
+![Screenshot](3d_viewer_screenshot.png)
+
+To use it, from within `/port/PyAssimp`:
+
+```
+$ cd scripts
+$ python ./3D-viewer <path to your model>
+```
+
+You can use this code as starting point in your applications.
+
+### Writing your own code
+
+To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`,
+which illustrates the basic usage. All Assimp data structures are wrapped using
+`ctypes`. All the data+length fields in Assimp's data structures (such as
+`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python
+lists, so you can call `len()` on them to get their respective size and access
+members using `[]`.
+
+For example, to load a file named `hello.3ds` and print the first
+vertex of the first mesh, you would do (proper error handling
+substituted by assertions ...):
+
+```python
+
+from pyassimp import *
+scene = load('hello.3ds')
+
+assert len(scene.meshes)
+mesh = scene.meshes[0]
+
+assert len(mesh.vertices)
+print(mesh.vertices[0])
+
+# don't forget this one, or you will leak!
+release(scene)
+
+```
+
+Another example to list the 'top nodes' in a
+scene:
+
+```python
+
+from pyassimp import *
+scene = load('hello.3ds')
+
+for c in scene.rootnode.children:
+    print(str(c))
+
+release(scene)
+
+```
+
+INSTALL
+-------
+
+Install `pyassimp` by running:
+
+```
+$ python setup.py install
+```
+
+PyAssimp requires a assimp dynamic library (`DLL` on windows,
+`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories 
+are:
+
+- the current directory
+- on linux additionally: `/usr/lib`, `/usr/local/lib`,
+  `/usr/lib/x86_64-linux-gnu`
+
+To build that library, refer to the Assimp master `INSTALL`
+instructions. To look in more places, edit `./pyassimp/helper.py`.
+There's an `additional_dirs` list waiting for your entries.
+

+ 1 - 1
port/PyAssimp/scripts/3d_viewer.py

@@ -679,7 +679,7 @@ class PyAssimp3DViewer:
         logger.info("Loading model:" + path + "...")
 
         if postprocess:
-            self.scene = pyassimp.load(path, postprocess)
+            self.scene = pyassimp.load(path, processing=postprocess)
         else:
             self.scene = pyassimp.load(path)
         logger.info("Done.")

+ 1 - 1
port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py

@@ -98,7 +98,7 @@ class GLRenderer():
         logger.info("Loading model:" + path + "...")
 
         if postprocess:
-            self.scene = pyassimp.load(path, postprocess)
+            self.scene = pyassimp.load(path, processing=postprocess)
         else:
             self.scene = pyassimp.load(path)
         logger.info("Done.")

+ 1 - 1
port/PyAssimp/scripts/sample.py

@@ -20,7 +20,7 @@ def recur_node(node,level = 0):
 
 def main(filename=None):
 
-    scene = pyassimp.load(filename, pyassimp.postprocess.aiProcess_Triangulate)
+    scene = pyassimp.load(filename, processing=pyassimp.postprocess.aiProcess_Triangulate)
     
     #the model we load
     print("MODEL:" + filename)

+ 2 - 2
port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake

@@ -7,8 +7,8 @@ SET (CMAKE_SYSTEM_PROCESSOR "arm64")
 SET (SDKVER     "7.1")
 SET (DEVROOT    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain")
 SET (SDKROOT    "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVER}.sdk")
-SET (CC         "${DEVROOT}/usr/bin/llvm-gcc")
-SET (CXX        "${DEVROOT}/usr/bin/llvm-g++")
+SET (CC "${DEVROOT}/usr/bin/clang")
+SET (CXX "${DEVROOT}/usr/bin/clang++")
 
 CMAKE_FORCE_C_COMPILER          (${CC} LLVM)
 CMAKE_FORCE_CXX_COMPILER        (${CXX} LLVM)

+ 4 - 0
test/unit/ut3DSImportExport.cpp

@@ -53,7 +53,11 @@ public:
     virtual bool importerTest() {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/3DS/fels.3ds", 0 );
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
         return nullptr != scene;
+#else
+        return nullptr == scene;
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
     }
 };
 

+ 4 - 0
test/unit/utASEImportExport.cpp

@@ -53,7 +53,11 @@ public:
     virtual bool importerTest() {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/ASE/ThreeCubesGreen.ASE", 0 );
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
         return nullptr != scene;
+#else 
+        return nullptr == scene;
+#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
     }
 };
 

+ 1 - 0
test/unit/utBatchLoader.cpp

@@ -66,6 +66,7 @@ TEST_F( BatchLoaderTest, createTest ) {
     } catch ( ... ) {
         ok = false;
     }
+    EXPECT_TRUE( ok );
 }
 
 TEST_F( BatchLoaderTest, validateAccessTest ) {

+ 1 - 1
test/unit/utObjTools.cpp

@@ -109,8 +109,8 @@ TEST_F( utObjTools, countComponents_TwoLines_Success ) {
     buffer.resize( data.size() );
     ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() );
     test_parser.setBuffer( buffer );
-    static const size_t Size = 4096UL;
 
     size_t numComps = test_parser.testGetNumComponentsInDataDefinition();
     EXPECT_EQ( 3U, numComps );
 }
+

+ 2 - 4
test/unit/utglTFImportExport.cpp

@@ -50,10 +50,8 @@ class utglTFImportExport : public AbstractImportExportBase {
 public:
     virtual bool importerTest() {
         Assimp::Importer importer;
-        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glFT/TwoBoxes/TwoBoxes.gltf", 0 );
-        //return nullptr != scene;
-
-        return true;
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", 0 );
+        return nullptr != scene;
     }
 };